Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/s390/include/asm/ap.h
26493 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
/*
3
* Adjunct processor (AP) interfaces
4
*
5
* Copyright IBM Corp. 2017
6
*
7
* Author(s): Tony Krowiak <[email protected]>
8
* Martin Schwidefsky <[email protected]>
9
* Harald Freudenberger <[email protected]>
10
*/
11
12
#ifndef _ASM_S390_AP_H_
13
#define _ASM_S390_AP_H_
14
15
#include <linux/io.h>
16
#include <asm/asm-extable.h>
17
18
/**
19
* The ap_qid_t identifier of an ap queue.
20
* If the AP facilities test (APFT) facility is available,
21
* card and queue index are 8 bit values, otherwise
22
* card index is 6 bit and queue index a 4 bit value.
23
*/
24
typedef unsigned int ap_qid_t;
25
26
#define AP_MKQID(_card, _queue) (((_card) & 0xff) << 8 | ((_queue) & 0xff))
27
#define AP_QID_CARD(_qid) (((_qid) >> 8) & 0xff)
28
#define AP_QID_QUEUE(_qid) ((_qid) & 0xff)
29
30
/**
31
* struct ap_queue_status - Holds the AP queue status.
32
* @queue_empty: Shows if queue is empty
33
* @replies_waiting: Waiting replies
34
* @queue_full: Is 1 if the queue is full
35
* @irq_enabled: Shows if interrupts are enabled for the AP
36
* @response_code: Holds the 8 bit response code
37
*
38
* The ap queue status word is returned by all three AP functions
39
* (PQAP, NQAP and DQAP). There's a set of flags in the first
40
* byte, followed by a 1 byte response code.
41
*/
42
struct ap_queue_status {
43
unsigned int queue_empty : 1;
44
unsigned int replies_waiting : 1;
45
unsigned int queue_full : 1;
46
unsigned int : 3;
47
unsigned int async : 1;
48
unsigned int irq_enabled : 1;
49
unsigned int response_code : 8;
50
unsigned int : 16;
51
};
52
53
/*
54
* AP queue status reg union to access the reg1
55
* register with the lower 32 bits comprising the
56
* ap queue status.
57
*/
58
union ap_queue_status_reg {
59
unsigned long value;
60
struct {
61
u32 _pad;
62
struct ap_queue_status status;
63
};
64
};
65
66
/**
67
* ap_intructions_available() - Test if AP instructions are available.
68
*
69
* Returns true if the AP instructions are installed, otherwise false.
70
*/
71
static inline bool ap_instructions_available(void)
72
{
73
unsigned long reg0 = AP_MKQID(0, 0);
74
unsigned long reg1 = 0;
75
76
asm volatile(
77
" lgr 0,%[reg0]\n" /* qid into gr0 */
78
" lghi 1,0\n" /* 0 into gr1 */
79
" lghi 2,0\n" /* 0 into gr2 */
80
" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
81
"0: la %[reg1],1\n" /* 1 into reg1 */
82
"1:\n"
83
EX_TABLE(0b, 1b)
84
: [reg1] "+&d" (reg1)
85
: [reg0] "d" (reg0)
86
: "cc", "0", "1", "2");
87
return reg1 != 0;
88
}
89
90
/* TAPQ register GR2 response struct */
91
struct ap_tapq_hwinfo {
92
union {
93
unsigned long value;
94
struct {
95
unsigned int fac : 32; /* facility bits */
96
unsigned int apinfo : 32; /* ap type, ... */
97
};
98
struct {
99
unsigned int apsc : 1; /* APSC */
100
unsigned int mex4k : 1; /* AP4KM */
101
unsigned int crt4k : 1; /* AP4KC */
102
unsigned int cca : 1; /* D */
103
unsigned int accel : 1; /* A */
104
unsigned int ep11 : 1; /* X */
105
unsigned int apxa : 1; /* APXA */
106
unsigned int slcf : 1; /* Cmd filtering avail. */
107
unsigned int class : 8;
108
unsigned int bs : 2; /* SE bind/assoc */
109
unsigned int : 14;
110
unsigned int at : 8; /* ap type */
111
unsigned int nd : 8; /* nr of domains */
112
unsigned int : 4;
113
unsigned int ml : 4; /* apxl ml */
114
unsigned int : 4;
115
unsigned int qd : 4; /* queue depth */
116
};
117
};
118
};
119
120
/*
121
* Convenience defines to be used with the bs field from struct ap_tapq_gr2
122
*/
123
#define AP_BS_Q_USABLE 0
124
#define AP_BS_Q_USABLE_NO_SECURE_KEY 1
125
#define AP_BS_Q_AVAIL_FOR_BINDING 2
126
#define AP_BS_Q_UNUSABLE 3
127
128
/**
129
* ap_tapq(): Test adjunct processor queue.
130
* @qid: The AP queue number
131
* @info: Pointer to tapq hwinfo struct
132
*
133
* Returns AP queue status structure.
134
*/
135
static inline struct ap_queue_status ap_tapq(ap_qid_t qid,
136
struct ap_tapq_hwinfo *info)
137
{
138
union ap_queue_status_reg reg1;
139
unsigned long reg2;
140
141
asm volatile(
142
" lgr 0,%[qid]\n" /* qid into gr0 */
143
" lghi 2,0\n" /* 0 into gr2 */
144
" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
145
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
146
" lgr %[reg2],2\n" /* gr2 into reg2 */
147
: [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2)
148
: [qid] "d" (qid)
149
: "cc", "0", "1", "2");
150
if (info)
151
info->value = reg2;
152
return reg1.status;
153
}
154
155
/**
156
* ap_test_queue(): Test adjunct processor queue.
157
* @qid: The AP queue number
158
* @tbit: Test facilities bit
159
* @info: Ptr to tapq gr2 struct
160
*
161
* Returns AP queue status structure.
162
*/
163
static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit,
164
struct ap_tapq_hwinfo *info)
165
{
166
if (tbit)
167
qid |= 1UL << 23; /* set T bit*/
168
return ap_tapq(qid, info);
169
}
170
171
/**
172
* ap_pqap_rapq(): Reset adjunct processor queue.
173
* @qid: The AP queue number
174
* @fbit: if != 0 set F bit
175
*
176
* Returns AP queue status structure.
177
*/
178
static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit)
179
{
180
unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */
181
union ap_queue_status_reg reg1;
182
183
if (fbit)
184
reg0 |= 1UL << 22;
185
186
asm volatile(
187
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
188
" .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */
189
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
190
: [reg1] "=&d" (reg1.value)
191
: [reg0] "d" (reg0)
192
: "cc", "0", "1");
193
return reg1.status;
194
}
195
196
/**
197
* ap_pqap_zapq(): Reset and zeroize adjunct processor queue.
198
* @qid: The AP queue number
199
* @fbit: if != 0 set F bit
200
*
201
* Returns AP queue status structure.
202
*/
203
static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit)
204
{
205
unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */
206
union ap_queue_status_reg reg1;
207
208
if (fbit)
209
reg0 |= 1UL << 22;
210
211
asm volatile(
212
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
213
" .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */
214
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
215
: [reg1] "=&d" (reg1.value)
216
: [reg0] "d" (reg0)
217
: "cc", "0", "1");
218
return reg1.status;
219
}
220
221
/**
222
* struct ap_config_info - convenience struct for AP crypto
223
* config info as returned by the ap_qci() function.
224
*/
225
struct ap_config_info {
226
union {
227
unsigned int flags;
228
struct {
229
unsigned int apsc : 1; /* S bit */
230
unsigned int apxa : 1; /* N bit */
231
unsigned int qact : 1; /* C bit */
232
unsigned int rc8a : 1; /* R bit */
233
unsigned int : 4;
234
unsigned int apsb : 1; /* B bit */
235
unsigned int : 23;
236
};
237
};
238
unsigned char na; /* max # of APs - 1 */
239
unsigned char nd; /* max # of Domains - 1 */
240
unsigned char _reserved0[10];
241
unsigned int apm[8]; /* AP ID mask */
242
unsigned int aqm[8]; /* AP (usage) queue mask */
243
unsigned int adm[8]; /* AP (control) domain mask */
244
unsigned char _reserved1[16];
245
} __aligned(8);
246
247
/**
248
* ap_qci(): Get AP configuration data
249
*
250
* Returns 0 on success, or -EOPNOTSUPP.
251
*/
252
static inline int ap_qci(struct ap_config_info *config)
253
{
254
unsigned long reg0 = 4UL << 24; /* fc 4UL is QCI */
255
unsigned long reg1 = -EOPNOTSUPP;
256
struct ap_config_info *reg2 = config;
257
258
asm volatile(
259
" lgr 0,%[reg0]\n" /* QCI fc into gr0 */
260
" lgr 2,%[reg2]\n" /* ptr to config into gr2 */
261
" .insn rre,0xb2af0000,0,0\n" /* PQAP(QCI) */
262
"0: la %[reg1],0\n" /* good case, QCI fc available */
263
"1:\n"
264
EX_TABLE(0b, 1b)
265
: [reg1] "+&d" (reg1)
266
: [reg0] "d" (reg0), [reg2] "d" (reg2)
267
: "cc", "memory", "0", "2");
268
269
return reg1;
270
}
271
272
/*
273
* struct ap_qirq_ctrl - convenient struct for easy invocation
274
* of the ap_aqic() function. This struct is passed as GR1
275
* parameter to the PQAP(AQIC) instruction. For details please
276
* see the AR documentation.
277
*/
278
union ap_qirq_ctrl {
279
unsigned long value;
280
struct {
281
unsigned int : 8;
282
unsigned int zone : 8; /* zone info */
283
unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */
284
unsigned int : 4;
285
unsigned int gisc : 3; /* guest isc field */
286
unsigned int : 6;
287
unsigned int gf : 2; /* gisa format */
288
unsigned int : 1;
289
unsigned int gisa : 27; /* gisa origin */
290
unsigned int : 1;
291
unsigned int isc : 3; /* irq sub class */
292
};
293
};
294
295
/**
296
* ap_aqic(): Control interruption for a specific AP.
297
* @qid: The AP queue number
298
* @qirqctrl: struct ap_qirq_ctrl (64 bit value)
299
* @pa_ind: Physical address of the notification indicator byte
300
*
301
* Returns AP queue status.
302
*/
303
static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
304
union ap_qirq_ctrl qirqctrl,
305
phys_addr_t pa_ind)
306
{
307
unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */
308
union ap_queue_status_reg reg1;
309
unsigned long reg2 = pa_ind;
310
311
reg1.value = qirqctrl.value;
312
313
asm volatile(
314
" lgr 0,%[reg0]\n" /* qid param into gr0 */
315
" lgr 1,%[reg1]\n" /* irq ctrl into gr1 */
316
" lgr 2,%[reg2]\n" /* ni addr into gr2 */
317
" .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */
318
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
319
: [reg1] "+&d" (reg1.value)
320
: [reg0] "d" (reg0), [reg2] "d" (reg2)
321
: "cc", "memory", "0", "1", "2");
322
323
return reg1.status;
324
}
325
326
/*
327
* union ap_qact_ap_info - used together with the
328
* ap_aqic() function to provide a convenient way
329
* to handle the ap info needed by the qact function.
330
*/
331
union ap_qact_ap_info {
332
unsigned long val;
333
struct {
334
unsigned int : 3;
335
unsigned int mode : 3;
336
unsigned int : 26;
337
unsigned int cat : 8;
338
unsigned int : 8;
339
unsigned char ver[2];
340
};
341
};
342
343
/**
344
* ap_qact(): Query AP compatibility type.
345
* @qid: The AP queue number
346
* @apinfo: On input the info about the AP queue. On output the
347
* alternate AP queue info provided by the qact function
348
* in GR2 is stored in.
349
*
350
* Returns AP queue status. Check response_code field for failures.
351
*/
352
static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
353
union ap_qact_ap_info *apinfo)
354
{
355
unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22);
356
union ap_queue_status_reg reg1;
357
unsigned long reg2;
358
359
reg1.value = apinfo->val;
360
361
asm volatile(
362
" lgr 0,%[reg0]\n" /* qid param into gr0 */
363
" lgr 1,%[reg1]\n" /* qact in info into gr1 */
364
" .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */
365
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
366
" lgr %[reg2],2\n" /* qact out info into reg2 */
367
: [reg1] "+&d" (reg1.value), [reg2] "=&d" (reg2)
368
: [reg0] "d" (reg0)
369
: "cc", "0", "1", "2");
370
apinfo->val = reg2;
371
return reg1.status;
372
}
373
374
/*
375
* ap_bapq(): SE bind AP queue.
376
* @qid: The AP queue number
377
*
378
* Returns AP queue status structure.
379
*
380
* Invoking this function in a non-SE environment
381
* may case a specification exception.
382
*/
383
static inline struct ap_queue_status ap_bapq(ap_qid_t qid)
384
{
385
unsigned long reg0 = qid | (7UL << 24); /* fc 7 is BAPQ */
386
union ap_queue_status_reg reg1;
387
388
asm volatile(
389
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
390
" .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */
391
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
392
: [reg1] "=&d" (reg1.value)
393
: [reg0] "d" (reg0)
394
: "cc", "0", "1");
395
396
return reg1.status;
397
}
398
399
/*
400
* ap_aapq(): SE associate AP queue.
401
* @qid: The AP queue number
402
* @sec_idx: The secret index
403
*
404
* Returns AP queue status structure.
405
*
406
* Invoking this function in a non-SE environment
407
* may case a specification exception.
408
*/
409
static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx)
410
{
411
unsigned long reg0 = qid | (8UL << 24); /* fc 8 is AAPQ */
412
unsigned long reg2 = sec_idx;
413
union ap_queue_status_reg reg1;
414
415
asm volatile(
416
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
417
" lgr 2,%[reg2]\n" /* secret index into gr2 */
418
" .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */
419
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
420
: [reg1] "=&d" (reg1.value)
421
: [reg0] "d" (reg0), [reg2] "d" (reg2)
422
: "cc", "0", "1", "2");
423
424
return reg1.status;
425
}
426
427
/**
428
* ap_nqap(): Send message to adjunct processor queue.
429
* @qid: The AP queue number
430
* @psmid: The program supplied message identifier
431
* @msg: The message text
432
* @length: The message length
433
*
434
* Returns AP queue status structure.
435
* Condition code 1 on NQAP can't happen because the L bit is 1.
436
* Condition code 2 on NQAP also means the send is incomplete,
437
* because a segment boundary was reached. The NQAP is repeated.
438
*/
439
static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
440
unsigned long long psmid,
441
void *msg, size_t length)
442
{
443
unsigned long reg0 = qid | 0x40000000UL; /* 0x4... is last msg part */
444
union register_pair nqap_r1, nqap_r2;
445
union ap_queue_status_reg reg1;
446
447
nqap_r1.even = (unsigned int)(psmid >> 32);
448
nqap_r1.odd = psmid & 0xffffffff;
449
nqap_r2.even = (unsigned long)msg;
450
nqap_r2.odd = (unsigned long)length;
451
452
asm volatile (
453
" lgr 0,%[reg0]\n" /* qid param in gr0 */
454
"0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n"
455
" brc 2,0b\n" /* handle partial completion */
456
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
457
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
458
[nqap_r2] "+&d" (nqap_r2.pair)
459
: [nqap_r1] "d" (nqap_r1.pair)
460
: "cc", "memory", "0", "1");
461
return reg1.status;
462
}
463
464
/**
465
* ap_dqap(): Receive message from adjunct processor queue.
466
* @qid: The AP queue number
467
* @psmid: Pointer to program supplied message identifier
468
* @msg: Pointer to message buffer
469
* @msglen: Message buffer size
470
* @length: Pointer to length of actually written bytes
471
* @reslength: Residual length on return
472
* @resgr0: input: gr0 value (only used if != 0), output: residual gr0 content
473
*
474
* Returns AP queue status structure.
475
* Condition code 1 on DQAP means the receive has taken place
476
* but only partially. The response is incomplete, hence the
477
* DQAP is repeated.
478
* Condition code 2 on DQAP also means the receive is incomplete,
479
* this time because a segment boundary was reached. Again, the
480
* DQAP is repeated.
481
* Note that gpr2 is used by the DQAP instruction to keep track of
482
* any 'residual' length, in case the instruction gets interrupted.
483
* Hence it gets zeroed before the instruction.
484
* If the message does not fit into the buffer, this function will
485
* return with a truncated message and the reply in the firmware queue
486
* is not removed. This is indicated to the caller with an
487
* ap_queue_status response_code value of all bits on (0xFF) and (if
488
* the reslength ptr is given) the remaining length is stored in
489
* *reslength and (if the resgr0 ptr is given) the updated gr0 value
490
* for further processing of this msg entry is stored in *resgr0. The
491
* caller needs to detect this situation and should invoke ap_dqap
492
* with a valid resgr0 ptr and a value in there != 0 to indicate that
493
* *resgr0 is to be used instead of qid to further process this entry.
494
*/
495
static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
496
unsigned long *psmid,
497
void *msg, size_t msglen,
498
size_t *length,
499
size_t *reslength,
500
unsigned long *resgr0)
501
{
502
unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;
503
union ap_queue_status_reg reg1;
504
unsigned long reg2;
505
union register_pair rp1, rp2;
506
507
rp1.even = 0UL;
508
rp1.odd = 0UL;
509
rp2.even = (unsigned long)msg;
510
rp2.odd = (unsigned long)msglen;
511
512
asm volatile(
513
" lgr 0,%[reg0]\n" /* qid param into gr0 */
514
" lghi 2,0\n" /* 0 into gr2 (res length) */
515
"0: ltgr %N[rp2],%N[rp2]\n" /* check buf len */
516
" jz 2f\n" /* go out if buf len is 0 */
517
"1: .insn rre,0xb2ae0000,%[rp1],%[rp2]\n"
518
" brc 6,0b\n" /* handle partial complete */
519
"2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */
520
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
521
" lgr %[reg2],2\n" /* gr2 (res length) into reg2 */
522
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
523
[reg2] "=&d" (reg2), [rp1] "+&d" (rp1.pair),
524
[rp2] "+&d" (rp2.pair)
525
:
526
: "cc", "memory", "0", "1", "2");
527
528
if (reslength)
529
*reslength = reg2;
530
if (reg2 != 0 && rp2.odd == 0) {
531
/*
532
* Partially complete, status in gr1 is not set.
533
* Signal the caller that this dqap is only partially received
534
* with a special status response code 0xFF and *resgr0 updated
535
*/
536
reg1.status.response_code = 0xFF;
537
if (resgr0)
538
*resgr0 = reg0;
539
} else {
540
*psmid = (rp1.even << 32) + rp1.odd;
541
if (resgr0)
542
*resgr0 = 0;
543
}
544
545
/* update *length with the nr of bytes stored into the msg buffer */
546
if (length)
547
*length = msglen - rp2.odd;
548
549
return reg1.status;
550
}
551
552
#endif /* _ASM_S390_AP_H_ */
553
554