aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-09-21 06:48:54 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-12-14 10:33:38 -0500
commit0db78559f965a2e652dbe8acf35333f2081bf872 (patch)
tree7e7fbcb64807bf69f67a332f061f0f2cc7d3a587
parent236fb2ab95e9832880501d465d64eb2f2935b852 (diff)
s390/zcrypt: header for the AP inline assmblies
Move the inline assemblies for the AP bus into a separate header file. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/crypto/ap_asm.h191
-rw-r--r--drivers/s390/crypto/ap_bus.c188
2 files changed, 204 insertions, 175 deletions
diff --git a/drivers/s390/crypto/ap_asm.h b/drivers/s390/crypto/ap_asm.h
new file mode 100644
index 000000000000..12fffdd1e8e8
--- /dev/null
+++ b/drivers/s390/crypto/ap_asm.h
@@ -0,0 +1,191 @@
1/*
2 * Copyright IBM Corp. 2016
3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
4 *
5 * Adjunct processor bus inline assemblies.
6 */
7
8#ifndef _AP_ASM_H_
9#define _AP_ASM_H_
10
11#include <asm/isc.h>
12
13/**
14 * ap_intructions_available() - Test if AP instructions are available.
15 *
16 * Returns 0 if the AP instructions are installed.
17 */
18static inline int ap_instructions_available(void)
19{
20 register unsigned long reg0 asm ("0") = AP_MKQID(0, 0);
21 register unsigned long reg1 asm ("1") = -ENODEV;
22 register unsigned long reg2 asm ("2") = 0UL;
23
24 asm volatile(
25 " .long 0xb2af0000\n" /* PQAP(TAPQ) */
26 "0: la %1,0\n"
27 "1:\n"
28 EX_TABLE(0b, 1b)
29 : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc");
30 return reg1;
31}
32
33/**
34 * ap_tapq(): Test adjunct processor queue.
35 * @qid: The AP queue number
36 * @info: Pointer to queue descriptor
37 *
38 * Returns AP queue status structure.
39 */
40static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info)
41{
42 register unsigned long reg0 asm ("0") = qid;
43 register struct ap_queue_status reg1 asm ("1");
44 register unsigned long reg2 asm ("2") = 0UL;
45
46 asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */
47 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
48 if (info)
49 *info = reg2;
50 return reg1;
51}
52
53/**
54 * ap_pqap_rapq(): Reset adjunct processor queue.
55 * @qid: The AP queue number
56 *
57 * Returns AP queue status structure.
58 */
59static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
60{
61 register unsigned long reg0 asm ("0") = qid | 0x01000000UL;
62 register struct ap_queue_status reg1 asm ("1");
63 register unsigned long reg2 asm ("2") = 0UL;
64
65 asm volatile(
66 ".long 0xb2af0000" /* PQAP(RAPQ) */
67 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
68 return reg1;
69}
70
71/**
72 * ap_aqic(): Enable interruption for a specific AP.
73 * @qid: The AP queue number
74 * @ind: The notification indicator byte
75 *
76 * Returns AP queue status.
77 */
78static inline struct ap_queue_status ap_aqic(ap_qid_t qid, void *ind)
79{
80 register unsigned long reg0 asm ("0") = qid | (3UL << 24);
81 register unsigned long reg1_in asm ("1") = (8UL << 44) | AP_ISC;
82 register struct ap_queue_status reg1_out asm ("1");
83 register void *reg2 asm ("2") = ind;
84
85 asm volatile(
86 ".long 0xb2af0000" /* PQAP(AQIC) */
87 : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2)
88 :
89 : "cc");
90 return reg1_out;
91}
92
93/**
94 * ap_qci(): Get AP configuration data
95 *
96 * Returns 0 on success, or -EOPNOTSUPP.
97 */
98static inline int ap_qci(void *config)
99{
100 register unsigned long reg0 asm ("0") = 0x04000000UL;
101 register unsigned long reg1 asm ("1") = -EINVAL;
102 register void *reg2 asm ("2") = (void *) config;
103
104 asm volatile(
105 ".long 0xb2af0000\n" /* PQAP(QCI) */
106 "0: la %1,0\n"
107 "1:\n"
108 EX_TABLE(0b, 1b)
109 : "+d" (reg0), "+d" (reg1), "+d" (reg2)
110 :
111 : "cc");
112
113 return reg1;
114}
115
116/**
117 * ap_nqap(): Send message to adjunct processor queue.
118 * @qid: The AP queue number
119 * @psmid: The program supplied message identifier
120 * @msg: The message text
121 * @length: The message length
122 *
123 * Returns AP queue status structure.
124 * Condition code 1 on NQAP can't happen because the L bit is 1.
125 * Condition code 2 on NQAP also means the send is incomplete,
126 * because a segment boundary was reached. The NQAP is repeated.
127 */
128static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
129 unsigned long long psmid,
130 void *msg, size_t length)
131{
132 struct msgblock { char _[length]; };
133 register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
134 register struct ap_queue_status reg1 asm ("1");
135 register unsigned long reg2 asm ("2") = (unsigned long) msg;
136 register unsigned long reg3 asm ("3") = (unsigned long) length;
137 register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
138 register unsigned long reg5 asm ("5") = psmid & 0xffffffff;
139
140 asm volatile (
141 "0: .long 0xb2ad0042\n" /* NQAP */
142 " brc 2,0b"
143 : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
144 : "d" (reg4), "d" (reg5), "m" (*(struct msgblock *) msg)
145 : "cc");
146 return reg1;
147}
148
149/**
150 * ap_dqap(): Receive message from adjunct processor queue.
151 * @qid: The AP queue number
152 * @psmid: Pointer to program supplied message identifier
153 * @msg: The message text
154 * @length: The message length
155 *
156 * Returns AP queue status structure.
157 * Condition code 1 on DQAP means the receive has taken place
158 * but only partially. The response is incomplete, hence the
159 * DQAP is repeated.
160 * Condition code 2 on DQAP also means the receive is incomplete,
161 * this time because a segment boundary was reached. Again, the
162 * DQAP is repeated.
163 * Note that gpr2 is used by the DQAP instruction to keep track of
164 * any 'residual' length, in case the instruction gets interrupted.
165 * Hence it gets zeroed before the instruction.
166 */
167static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
168 unsigned long long *psmid,
169 void *msg, size_t length)
170{
171 struct msgblock { char _[length]; };
172 register unsigned long reg0 asm("0") = qid | 0x80000000UL;
173 register struct ap_queue_status reg1 asm ("1");
174 register unsigned long reg2 asm("2") = 0UL;
175 register unsigned long reg4 asm("4") = (unsigned long) msg;
176 register unsigned long reg5 asm("5") = (unsigned long) length;
177 register unsigned long reg6 asm("6") = 0UL;
178 register unsigned long reg7 asm("7") = 0UL;
179
180
181 asm volatile(
182 "0: .long 0xb2ae0064\n" /* DQAP */
183 " brc 6,0b\n"
184 : "+d" (reg0), "=d" (reg1), "+d" (reg2),
185 "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7),
186 "=m" (*(struct msgblock *) msg) : : "cc");
187 *psmid = (((unsigned long long) reg6) << 32) + reg7;
188 return reg1;
189}
190
191#endif /* _AP_ASM_H_ */
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index c695219d70c4..f6de22a4f7d9 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -48,6 +48,7 @@
48#include <linux/crypto.h> 48#include <linux/crypto.h>
49 49
50#include "ap_bus.h" 50#include "ap_bus.h"
51#include "ap_asm.h"
51 52
52/* 53/*
53 * Module description. 54 * Module description.
@@ -130,26 +131,6 @@ static inline int ap_using_interrupts(void)
130} 131}
131 132
132/** 133/**
133 * ap_intructions_available() - Test if AP instructions are available.
134 *
135 * Returns 0 if the AP instructions are installed.
136 */
137static inline int ap_instructions_available(void)
138{
139 register unsigned long reg0 asm ("0") = AP_MKQID(0,0);
140 register unsigned long reg1 asm ("1") = -ENODEV;
141 register unsigned long reg2 asm ("2") = 0UL;
142
143 asm volatile(
144 " .long 0xb2af0000\n" /* PQAP(TAPQ) */
145 "0: la %1,0\n"
146 "1:\n"
147 EX_TABLE(0b, 1b)
148 : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc" );
149 return reg1;
150}
151
152/**
153 * ap_interrupts_available(): Test if AP interrupts are available. 134 * ap_interrupts_available(): Test if AP interrupts are available.
154 * 135 *
155 * Returns 1 if AP interrupts are available. 136 * Returns 1 if AP interrupts are available.
@@ -170,19 +151,6 @@ static int ap_configuration_available(void)
170 return test_facility(12); 151 return test_facility(12);
171} 152}
172 153
173static inline struct ap_queue_status
174__pqap_tapq(ap_qid_t qid, unsigned long *info)
175{
176 register unsigned long reg0 asm ("0") = qid;
177 register struct ap_queue_status reg1 asm ("1");
178 register unsigned long reg2 asm ("2") = 0UL;
179
180 asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */
181 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
182 *info = reg2;
183 return reg1;
184}
185
186/** 154/**
187 * ap_test_queue(): Test adjunct processor queue. 155 * ap_test_queue(): Test adjunct processor queue.
188 * @qid: The AP queue number 156 * @qid: The AP queue number
@@ -193,85 +161,16 @@ __pqap_tapq(ap_qid_t qid, unsigned long *info)
193static inline struct ap_queue_status 161static inline struct ap_queue_status
194ap_test_queue(ap_qid_t qid, unsigned long *info) 162ap_test_queue(ap_qid_t qid, unsigned long *info)
195{ 163{
196 struct ap_queue_status aqs;
197 unsigned long _info;
198
199 if (test_facility(15)) 164 if (test_facility(15))
200 qid |= 1UL << 23; /* set APFT T bit*/ 165 qid |= 1UL << 23; /* set APFT T bit*/
201 aqs = __pqap_tapq(qid, &_info); 166 return ap_tapq(qid, info);
202 if (info)
203 *info = _info;
204 return aqs;
205}
206
207/**
208 * ap_reset_queue(): Reset adjunct processor queue.
209 * @qid: The AP queue number
210 *
211 * Returns AP queue status structure.
212 */
213static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid)
214{
215 register unsigned long reg0 asm ("0") = qid | 0x01000000UL;
216 register struct ap_queue_status reg1 asm ("1");
217 register unsigned long reg2 asm ("2") = 0UL;
218
219 asm volatile(
220 ".long 0xb2af0000" /* PQAP(RAPQ) */
221 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
222 return reg1;
223}
224
225/**
226 * ap_queue_interruption_control(): Enable interruption for a specific AP.
227 * @qid: The AP queue number
228 * @ind: The notification indicator byte
229 *
230 * Returns AP queue status.
231 */
232static inline struct ap_queue_status
233ap_queue_interruption_control(ap_qid_t qid, void *ind)
234{
235 register unsigned long reg0 asm ("0") = qid | 0x03000000UL;
236 register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC;
237 register struct ap_queue_status reg1_out asm ("1");
238 register void *reg2 asm ("2") = ind;
239 asm volatile(
240 ".long 0xb2af0000" /* PQAP(AQIC) */
241 : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2)
242 :
243 : "cc" );
244 return reg1_out;
245}
246
247/**
248 * ap_query_configuration(): Get AP configuration data
249 *
250 * Returns 0 on success, or -EOPNOTSUPP.
251 */
252static inline int __ap_query_configuration(void)
253{
254 register unsigned long reg0 asm ("0") = 0x04000000UL;
255 register unsigned long reg1 asm ("1") = -EINVAL;
256 register void *reg2 asm ("2") = (void *) ap_configuration;
257
258 asm volatile(
259 ".long 0xb2af0000\n" /* PQAP(QCI) */
260 "0: la %1,0\n"
261 "1:\n"
262 EX_TABLE(0b, 1b)
263 : "+d" (reg0), "+d" (reg1), "+d" (reg2)
264 :
265 : "cc");
266
267 return reg1;
268} 167}
269 168
270static inline int ap_query_configuration(void) 169static inline int ap_query_configuration(void)
271{ 170{
272 if (!ap_configuration) 171 if (!ap_configuration)
273 return -EOPNOTSUPP; 172 return -EOPNOTSUPP;
274 return __ap_query_configuration(); 173 return ap_qci(ap_configuration);
275} 174}
276 175
277/** 176/**
@@ -336,15 +235,15 @@ static inline int ap_test_config_domain(unsigned int domain)
336 * @qid: The AP queue number 235 * @qid: The AP queue number
337 * @ind: the notification indicator byte 236 * @ind: the notification indicator byte
338 * 237 *
339 * Enables interruption on AP queue via ap_queue_interruption_control(). Based 238 * Enables interruption on AP queue via ap_aqic(). Based on the return
340 * on the return value it waits a while and tests the AP queue if interrupts 239 * value it waits a while and tests the AP queue if interrupts
341 * have been switched on using ap_test_queue(). 240 * have been switched on using ap_test_queue().
342 */ 241 */
343static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind) 242static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind)
344{ 243{
345 struct ap_queue_status status; 244 struct ap_queue_status status;
346 245
347 status = ap_queue_interruption_control(ap_dev->qid, ind); 246 status = ap_aqic(ap_dev->qid, ind);
348 switch (status.response_code) { 247 switch (status.response_code) {
349 case AP_RESPONSE_NORMAL: 248 case AP_RESPONSE_NORMAL:
350 case AP_RESPONSE_OTHERWISE_CHANGED: 249 case AP_RESPONSE_OTHERWISE_CHANGED:
@@ -363,26 +262,6 @@ static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind)
363 } 262 }
364} 263}
365 264
366static inline struct ap_queue_status
367__nqap(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
368{
369 typedef struct { char _[length]; } msgblock;
370 register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
371 register struct ap_queue_status reg1 asm ("1");
372 register unsigned long reg2 asm ("2") = (unsigned long) msg;
373 register unsigned long reg3 asm ("3") = (unsigned long) length;
374 register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
375 register unsigned long reg5 asm ("5") = psmid & 0xffffffff;
376
377 asm volatile (
378 "0: .long 0xb2ad0042\n" /* NQAP */
379 " brc 2,0b"
380 : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
381 : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg)
382 : "cc");
383 return reg1;
384}
385
386/** 265/**
387 * __ap_send(): Send message to adjunct processor queue. 266 * __ap_send(): Send message to adjunct processor queue.
388 * @qid: The AP queue number 267 * @qid: The AP queue number
@@ -402,7 +281,7 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
402{ 281{
403 if (special == 1) 282 if (special == 1)
404 qid |= 0x400000UL; 283 qid |= 0x400000UL;
405 return __nqap(qid, psmid, msg, length); 284 return ap_nqap(qid, psmid, msg, length);
406} 285}
407 286
408int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) 287int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
@@ -424,54 +303,13 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
424} 303}
425EXPORT_SYMBOL(ap_send); 304EXPORT_SYMBOL(ap_send);
426 305
427/**
428 * __ap_recv(): Receive message from adjunct processor queue.
429 * @qid: The AP queue number
430 * @psmid: Pointer to 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 DQAP means the receive has taken place
436 * but only partially. The response is incomplete, hence the
437 * DQAP is repeated.
438 * Condition code 2 on DQAP also means the receive is incomplete,
439 * this time because a segment boundary was reached. Again, the
440 * DQAP is repeated.
441 * Note that gpr2 is used by the DQAP instruction to keep track of
442 * any 'residual' length, in case the instruction gets interrupted.
443 * Hence it gets zeroed before the instruction.
444 */
445static inline struct ap_queue_status
446__ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
447{
448 typedef struct { char _[length]; } msgblock;
449 register unsigned long reg0 asm("0") = qid | 0x80000000UL;
450 register struct ap_queue_status reg1 asm ("1");
451 register unsigned long reg2 asm("2") = 0UL;
452 register unsigned long reg4 asm("4") = (unsigned long) msg;
453 register unsigned long reg5 asm("5") = (unsigned long) length;
454 register unsigned long reg6 asm("6") = 0UL;
455 register unsigned long reg7 asm("7") = 0UL;
456
457
458 asm volatile(
459 "0: .long 0xb2ae0064\n" /* DQAP */
460 " brc 6,0b\n"
461 : "+d" (reg0), "=d" (reg1), "+d" (reg2),
462 "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7),
463 "=m" (*(msgblock *) msg) : : "cc" );
464 *psmid = (((unsigned long long) reg6) << 32) + reg7;
465 return reg1;
466}
467
468int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) 306int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
469{ 307{
470 struct ap_queue_status status; 308 struct ap_queue_status status;
471 309
472 if (msg == NULL) 310 if (msg == NULL)
473 return -EINVAL; 311 return -EINVAL;
474 status = __ap_recv(qid, psmid, msg, length); 312 status = ap_dqap(qid, psmid, msg, length);
475 switch (status.response_code) { 313 switch (status.response_code) {
476 case AP_RESPONSE_NORMAL: 314 case AP_RESPONSE_NORMAL:
477 return 0; 315 return 0;
@@ -577,8 +415,8 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev)
577 struct ap_queue_status status; 415 struct ap_queue_status status;
578 struct ap_message *ap_msg; 416 struct ap_message *ap_msg;
579 417
580 status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid, 418 status = ap_dqap(ap_dev->qid, &ap_dev->reply->psmid,
581 ap_dev->reply->message, ap_dev->reply->length); 419 ap_dev->reply->message, ap_dev->reply->length);
582 switch (status.response_code) { 420 switch (status.response_code) {
583 case AP_RESPONSE_NORMAL: 421 case AP_RESPONSE_NORMAL:
584 atomic_dec(&ap_poll_requests); 422 atomic_dec(&ap_poll_requests);
@@ -739,7 +577,7 @@ static enum ap_wait ap_sm_reset(struct ap_device *ap_dev)
739{ 577{
740 struct ap_queue_status status; 578 struct ap_queue_status status;
741 579
742 status = ap_reset_queue(ap_dev->qid); 580 status = ap_rapq(ap_dev->qid);
743 switch (status.response_code) { 581 switch (status.response_code) {
744 case AP_RESPONSE_NORMAL: 582 case AP_RESPONSE_NORMAL:
745 case AP_RESPONSE_RESET_IN_PROGRESS: 583 case AP_RESPONSE_RESET_IN_PROGRESS:
@@ -1794,7 +1632,7 @@ static void ap_reset_domain(void)
1794 if (ap_domain_index == -1 || !ap_test_config_domain(ap_domain_index)) 1632 if (ap_domain_index == -1 || !ap_test_config_domain(ap_domain_index))
1795 return; 1633 return;
1796 for (i = 0; i < AP_DEVICES; i++) 1634 for (i = 0; i < AP_DEVICES; i++)
1797 ap_reset_queue(AP_MKQID(i, ap_domain_index)); 1635 ap_rapq(AP_MKQID(i, ap_domain_index));
1798} 1636}
1799 1637
1800static void ap_reset_all(void) 1638static void ap_reset_all(void)
@@ -1807,7 +1645,7 @@ static void ap_reset_all(void)
1807 for (j = 0; j < AP_DEVICES; j++) { 1645 for (j = 0; j < AP_DEVICES; j++) {
1808 if (!ap_test_config_card_id(j)) 1646 if (!ap_test_config_card_id(j))
1809 continue; 1647 continue;
1810 ap_reset_queue(AP_MKQID(j, i)); 1648 ap_rapq(AP_MKQID(j, i));
1811 } 1649 }
1812 } 1650 }
1813} 1651}