diff options
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 8fd8c62455e..67302b944ab 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -27,6 +27,7 @@ #define KMSG_COMPONENT "ap" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/kernel_stat.h> #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> @@ -154,7 +155,7 @@ static inline int ap_instructions_available(void) */ static int ap_interrupts_available(void) { - return test_facility(1) && test_facility(2); + return test_facility(2) && test_facility(65); } /** @@ -221,6 +222,69 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind) } #endif +static inline struct ap_queue_status __ap_4096_commands_available(ap_qid_t qid, + int *support) +{ + register unsigned long reg0 asm ("0") = 0UL | qid | (1UL << 23); + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile( + ".long 0xb2af0000\n" + "0: la %1,0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (reg0), "=d" (reg1), "=d" (reg2) + : + : "cc"); + + if (reg2 & 0x6000000000000000ULL) + *support = 1; + else + *support = 0; + + return reg1; +} + +/** + * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA + * support. + * @qid: The AP queue number + * + * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not. + */ +int ap_4096_commands_available(ap_qid_t qid) +{ + struct ap_queue_status status; + int i, support = 0; + status = __ap_4096_commands_available(qid, &support); + + for (i = 0; i < AP_MAX_RESET; i++) { + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + return support; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + break; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_INVALID_ADDRESS: + return 0; + case AP_RESPONSE_OTHERWISE_CHANGED: + break; + default: + break; + } + if (i < AP_MAX_RESET - 1) { + udelay(5); + status = __ap_4096_commands_available(qid, &support); + } + } + return support; +} +EXPORT_SYMBOL(ap_4096_commands_available); + /** * ap_queue_enable_interruption(): Enable interruption on an AP. * @qid: The AP queue number @@ -1042,6 +1106,7 @@ out: static void ap_interrupt_handler(void *unused1, void *unused2) { + kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++; tasklet_schedule(&ap_tasklet); } |