diff options
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 82 |
1 files changed, 72 insertions, 10 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 91c6028d7b74..16e4a25596e7 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #define KMSG_COMPONENT "ap" | 27 | #define KMSG_COMPONENT "ap" |
28 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 28 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
29 | 29 | ||
30 | #include <linux/kernel_stat.h> | ||
30 | #include <linux/module.h> | 31 | #include <linux/module.h> |
31 | #include <linux/init.h> | 32 | #include <linux/init.h> |
32 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
@@ -154,14 +155,7 @@ static inline int ap_instructions_available(void) | |||
154 | */ | 155 | */ |
155 | static int ap_interrupts_available(void) | 156 | static int ap_interrupts_available(void) |
156 | { | 157 | { |
157 | unsigned long long facility_bits[2]; | 158 | return test_facility(2) && test_facility(65); |
158 | |||
159 | if (stfle(facility_bits, 2) <= 1) | ||
160 | return 0; | ||
161 | if (!(facility_bits[0] & (1ULL << 61)) || | ||
162 | !(facility_bits[1] & (1ULL << 62))) | ||
163 | return 0; | ||
164 | return 1; | ||
165 | } | 159 | } |
166 | 160 | ||
167 | /** | 161 | /** |
@@ -228,6 +222,69 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind) | |||
228 | } | 222 | } |
229 | #endif | 223 | #endif |
230 | 224 | ||
225 | static inline struct ap_queue_status __ap_4096_commands_available(ap_qid_t qid, | ||
226 | int *support) | ||
227 | { | ||
228 | register unsigned long reg0 asm ("0") = 0UL | qid | (1UL << 23); | ||
229 | register struct ap_queue_status reg1 asm ("1"); | ||
230 | register unsigned long reg2 asm ("2") = 0UL; | ||
231 | |||
232 | asm volatile( | ||
233 | ".long 0xb2af0000\n" | ||
234 | "0: la %1,0\n" | ||
235 | "1:\n" | ||
236 | EX_TABLE(0b, 1b) | ||
237 | : "+d" (reg0), "=d" (reg1), "=d" (reg2) | ||
238 | : | ||
239 | : "cc"); | ||
240 | |||
241 | if (reg2 & 0x6000000000000000ULL) | ||
242 | *support = 1; | ||
243 | else | ||
244 | *support = 0; | ||
245 | |||
246 | return reg1; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA | ||
251 | * support. | ||
252 | * @qid: The AP queue number | ||
253 | * | ||
254 | * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not. | ||
255 | */ | ||
256 | int ap_4096_commands_available(ap_qid_t qid) | ||
257 | { | ||
258 | struct ap_queue_status status; | ||
259 | int i, support = 0; | ||
260 | status = __ap_4096_commands_available(qid, &support); | ||
261 | |||
262 | for (i = 0; i < AP_MAX_RESET; i++) { | ||
263 | switch (status.response_code) { | ||
264 | case AP_RESPONSE_NORMAL: | ||
265 | return support; | ||
266 | case AP_RESPONSE_RESET_IN_PROGRESS: | ||
267 | case AP_RESPONSE_BUSY: | ||
268 | break; | ||
269 | case AP_RESPONSE_Q_NOT_AVAIL: | ||
270 | case AP_RESPONSE_DECONFIGURED: | ||
271 | case AP_RESPONSE_CHECKSTOPPED: | ||
272 | case AP_RESPONSE_INVALID_ADDRESS: | ||
273 | return 0; | ||
274 | case AP_RESPONSE_OTHERWISE_CHANGED: | ||
275 | break; | ||
276 | default: | ||
277 | break; | ||
278 | } | ||
279 | if (i < AP_MAX_RESET - 1) { | ||
280 | udelay(5); | ||
281 | status = __ap_4096_commands_available(qid, &support); | ||
282 | } | ||
283 | } | ||
284 | return support; | ||
285 | } | ||
286 | EXPORT_SYMBOL(ap_4096_commands_available); | ||
287 | |||
231 | /** | 288 | /** |
232 | * ap_queue_enable_interruption(): Enable interruption on an AP. | 289 | * ap_queue_enable_interruption(): Enable interruption on an AP. |
233 | * @qid: The AP queue number | 290 | * @qid: The AP queue number |
@@ -1049,6 +1106,7 @@ out: | |||
1049 | 1106 | ||
1050 | static void ap_interrupt_handler(void *unused1, void *unused2) | 1107 | static void ap_interrupt_handler(void *unused1, void *unused2) |
1051 | { | 1108 | { |
1109 | kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++; | ||
1052 | tasklet_schedule(&ap_tasklet); | 1110 | tasklet_schedule(&ap_tasklet); |
1053 | } | 1111 | } |
1054 | 1112 | ||
@@ -1125,8 +1183,12 @@ static void ap_scan_bus(struct work_struct *unused) | |||
1125 | INIT_LIST_HEAD(&ap_dev->list); | 1183 | INIT_LIST_HEAD(&ap_dev->list); |
1126 | setup_timer(&ap_dev->timeout, ap_request_timeout, | 1184 | setup_timer(&ap_dev->timeout, ap_request_timeout, |
1127 | (unsigned long) ap_dev); | 1185 | (unsigned long) ap_dev); |
1128 | if (device_type == 0) | 1186 | if (device_type == 0) { |
1129 | ap_probe_device_type(ap_dev); | 1187 | if (ap_probe_device_type(ap_dev)) { |
1188 | kfree(ap_dev); | ||
1189 | continue; | ||
1190 | } | ||
1191 | } | ||
1130 | else | 1192 | else |
1131 | ap_dev->device_type = device_type; | 1193 | ap_dev->device_type = device_type; |
1132 | 1194 | ||