From b3e8652bcbfa04807e44708d4d0c8cdad39c9215 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 12 Oct 2016 15:58:14 +0200 Subject: s390/zcrypt: Introduce CEX6 toleration Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 3 +++ drivers/s390/crypto/ap_bus.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index f407b4f9d0ba..cac919d63b43 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1708,6 +1708,9 @@ static void ap_scan_bus(struct work_struct *unused) ap_dev->queue_depth = queue_depth; ap_dev->raw_hwtype = device_type; ap_dev->device_type = device_type; + /* CEX6 toleration: map to CEX5 */ + if (device_type == AP_DEVICE_TYPE_CEX6) + ap_dev->device_type = AP_DEVICE_TYPE_CEX5; ap_dev->functions = device_functions; spin_lock_init(&ap_dev->lock); INIT_LIST_HEAD(&ap_dev->pendingq); diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index d7fdf5c024d7..fd66d2c450d5 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -105,6 +105,7 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) #define AP_DEVICE_TYPE_CEX3C 9 #define AP_DEVICE_TYPE_CEX4 10 #define AP_DEVICE_TYPE_CEX5 11 +#define AP_DEVICE_TYPE_CEX6 12 /* * Known function facilities -- cgit v1.2.3 From fc1d3f02544a6fd5f417921b57c663388586a17a Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:11:30 +0200 Subject: s390/zcrypt: Move the ap bus into kernel Move the ap bus into the kernel and make it general available. Additionally include the message types and the API layer as a preparation for the workload management facility. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/Makefile | 10 +++++----- drivers/s390/crypto/ap_bus.c | 27 +++++++++++++++++++++++++-- drivers/s390/crypto/zcrypt_api.c | 7 ++++++- drivers/s390/crypto/zcrypt_msgtype50.c | 6 +----- drivers/s390/crypto/zcrypt_msgtype50.h | 2 +- drivers/s390/crypto/zcrypt_msgtype6.c | 6 +----- drivers/s390/crypto/zcrypt_msgtype6.h | 2 +- 7 files changed, 40 insertions(+), 20 deletions(-) diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index b8ab18676e69..d0549fc87247 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -3,9 +3,9 @@ # ap-objs := ap_bus.o -# zcrypt_api depends on ap -obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o -# msgtype* depend on zcrypt_api -obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o -# adapter drivers depend on ap, zcrypt_api and msgtype* +obj-$(subst m,y,$(CONFIG_ZCRYPT)) += ap.o +# zcrypt_api.o and zcrypt_msgtype*.o depend on ap.o +zcrypt-objs := zcrypt_api.o zcrypt_msgtype6.o zcrypt_msgtype50.o +obj-$(CONFIG_ZCRYPT) += zcrypt.o +# adapter drivers depend on ap.o and zcrypt.o obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index cac919d63b43..c695219d70c4 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -62,6 +62,7 @@ MODULE_ALIAS_CRYPTO("z90crypt"); * Module parameter */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */ +static DEFINE_SPINLOCK(ap_domain_lock); module_param_named(domain, ap_domain_index, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(domain, "domain index for ap devices"); EXPORT_SYMBOL(ap_domain_index); @@ -1481,7 +1482,21 @@ static ssize_t ap_domain_show(struct bus_type *bus, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); } -static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL); +static ssize_t ap_domain_store(struct bus_type *bus, + const char *buf, size_t count) +{ + int domain; + + if (sscanf(buf, "%i\n", &domain) != 1 || + domain < 0 || domain > ap_max_domain_id) + return -EINVAL; + spin_lock_bh(&ap_domain_lock); + ap_domain_index = domain; + spin_unlock_bh(&ap_domain_lock); + return count; +} + +static BUS_ATTR(ap_domain, 0644, ap_domain_show, ap_domain_store); static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) { @@ -1623,9 +1638,12 @@ static int ap_select_domain(void) * the "domain=" parameter or the domain with the maximum number * of devices. */ - if (ap_domain_index >= 0) + spin_lock_bh(&ap_domain_lock); + if (ap_domain_index >= 0) { /* Domain has already been selected. */ + spin_unlock_bh(&ap_domain_lock); return 0; + } best_domain = -1; max_count = 0; for (i = 0; i < AP_DOMAINS; i++) { @@ -1647,8 +1665,10 @@ static int ap_select_domain(void) } if (best_domain >= 0){ ap_domain_index = best_domain; + spin_unlock_bh(&ap_domain_lock); return 0; } + spin_unlock_bh(&ap_domain_lock); return -ENODEV; } @@ -1677,6 +1697,8 @@ static void ap_scan_bus(struct work_struct *unused) if (ap_select_domain() != 0) goto out; + + spin_lock_bh(&ap_domain_lock); for (i = 0; i < AP_DEVICES; i++) { qid = AP_MKQID(i, ap_domain_index); dev = bus_find_device(&ap_bus_type, NULL, @@ -1753,6 +1775,7 @@ static void ap_scan_bus(struct work_struct *unused) continue; } } + spin_unlock_bh(&ap_domain_lock); out: mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 5d3d04c040c2..7f61ae1b0b93 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -45,6 +45,7 @@ #include "zcrypt_api.h" #include "zcrypt_msgtype6.h" +#include "zcrypt_msgtype50.h" /* * Module description. @@ -1459,6 +1460,8 @@ int __init zcrypt_api_init(void) goto out_misc; } + zcrypt_msgtype6_init(); + zcrypt_msgtype50_init(); return 0; out_misc: @@ -1472,11 +1475,13 @@ out: * * The module termination code. */ -void zcrypt_api_exit(void) +void __exit zcrypt_api_exit(void) { remove_proc_entry("driver/z90crypt", NULL); misc_deregister(&zcrypt_misc_device); zcrypt_debug_exit(); + zcrypt_msgtype6_exit(); + zcrypt_msgtype50_exit(); } module_init(zcrypt_api_init); diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index eedfaa2cf715..7bafba83390a 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -518,16 +518,12 @@ static struct zcrypt_ops zcrypt_msgtype50_ops = { .variant = MSGTYPE50_VARIANT_DEFAULT, }; -int __init zcrypt_msgtype50_init(void) +void __init zcrypt_msgtype50_init(void) { zcrypt_msgtype_register(&zcrypt_msgtype50_ops); - return 0; } void __exit zcrypt_msgtype50_exit(void) { zcrypt_msgtype_unregister(&zcrypt_msgtype50_ops); } - -module_init(zcrypt_msgtype50_init); -module_exit(zcrypt_msgtype50_exit); diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h index 0a66e4aeeb50..eeb41c0f34ae 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.h +++ b/drivers/s390/crypto/zcrypt_msgtype50.h @@ -35,7 +35,7 @@ #define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/ -int zcrypt_msgtype50_init(void); +void zcrypt_msgtype50_init(void); void zcrypt_msgtype50_exit(void); #endif /* _ZCRYPT_MSGTYPE50_H_ */ diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 21959719daef..f71949685ff5 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -1145,12 +1145,11 @@ static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = { .send_ep11_cprb = zcrypt_msgtype6_send_ep11_cprb, }; -int __init zcrypt_msgtype6_init(void) +void __init zcrypt_msgtype6_init(void) { zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops); zcrypt_msgtype_register(&zcrypt_msgtype6_ops); zcrypt_msgtype_register(&zcrypt_msgtype6_ep11_ops); - return 0; } void __exit zcrypt_msgtype6_exit(void) @@ -1159,6 +1158,3 @@ void __exit zcrypt_msgtype6_exit(void) zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops); zcrypt_msgtype_unregister(&zcrypt_msgtype6_ep11_ops); } - -module_init(zcrypt_msgtype6_init); -module_exit(zcrypt_msgtype6_exit); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index 207247570623..5750c4377bfa 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -165,7 +165,7 @@ static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, ap_msg->length = sizeof(*msg); } -int zcrypt_msgtype6_init(void); +void zcrypt_msgtype6_init(void); void zcrypt_msgtype6_exit(void); #endif /* _ZCRYPT_MSGTYPE6_H_ */ -- cgit v1.2.3 From 236fb2ab95e9832880501d465d64eb2f2935b852 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 2 Sep 2016 15:21:45 +0200 Subject: s390/zcrypt: simplify message type handling Now that the message type modules are linked with the zcrypt_api into a single module the zcrypt_ops_list is initialized by the module init function of the zcyppt.ko module. After that the list is static and all message types are present. Drop the zcrypt_ops_list_lock spinlock and the module handling in regard to the message types. Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 49 +++++-------------------------------- drivers/s390/crypto/zcrypt_api.h | 3 +-- drivers/s390/crypto/zcrypt_cex2a.c | 6 +---- drivers/s390/crypto/zcrypt_cex4.c | 16 +++++------- drivers/s390/crypto/zcrypt_pcixcc.c | 11 +++------ 5 files changed, 18 insertions(+), 67 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 7f61ae1b0b93..dc6d891a7b48 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -71,7 +71,6 @@ EXPORT_SYMBOL(zcrypt_rescan_req); static int zcrypt_rng_device_add(void); static void zcrypt_rng_device_remove(void); -static DEFINE_SPINLOCK(zcrypt_ops_list_lock); static LIST_HEAD(zcrypt_ops_list); static debug_info_t *zcrypt_dbf_common; @@ -318,61 +317,25 @@ EXPORT_SYMBOL(zcrypt_device_unregister); void zcrypt_msgtype_register(struct zcrypt_ops *zops) { - spin_lock_bh(&zcrypt_ops_list_lock); list_add_tail(&zops->list, &zcrypt_ops_list); - spin_unlock_bh(&zcrypt_ops_list_lock); } -EXPORT_SYMBOL(zcrypt_msgtype_register); void zcrypt_msgtype_unregister(struct zcrypt_ops *zops) { - spin_lock_bh(&zcrypt_ops_list_lock); list_del_init(&zops->list); - spin_unlock_bh(&zcrypt_ops_list_lock); } -EXPORT_SYMBOL(zcrypt_msgtype_unregister); -static inline -struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant) +struct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant) { struct zcrypt_ops *zops; - int found = 0; - spin_lock_bh(&zcrypt_ops_list_lock); - list_for_each_entry(zops, &zcrypt_ops_list, list) { + list_for_each_entry(zops, &zcrypt_ops_list, list) if ((zops->variant == variant) && - (!strncmp(zops->name, name, sizeof(zops->name)))) { - found = 1; - break; - } - } - if (!found || !try_module_get(zops->owner)) - zops = NULL; - - spin_unlock_bh(&zcrypt_ops_list_lock); - - return zops; -} - -struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant) -{ - struct zcrypt_ops *zops = NULL; - - zops = __ops_lookup(name, variant); - if (!zops) { - request_module("%s", name); - zops = __ops_lookup(name, variant); - } - return zops; -} -EXPORT_SYMBOL(zcrypt_msgtype_request); - -void zcrypt_msgtype_release(struct zcrypt_ops *zops) -{ - if (zops) - module_put(zops->owner); + (!strncmp(zops->name, name, sizeof(zops->name)))) + return zops; + return NULL; } -EXPORT_SYMBOL(zcrypt_msgtype_release); +EXPORT_SYMBOL(zcrypt_msgtype); /** * zcrypt_read (): Not supported beyond zcrypt 1.3.1. diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 38618f05ad92..326ecdc0417f 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -133,8 +133,7 @@ int zcrypt_device_register(struct zcrypt_device *); void zcrypt_device_unregister(struct zcrypt_device *); void zcrypt_msgtype_register(struct zcrypt_ops *); void zcrypt_msgtype_unregister(struct zcrypt_ops *); -struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *, int); -void zcrypt_msgtype_release(struct zcrypt_ops *); +struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int); int zcrypt_api_init(void); void zcrypt_api_exit(void); diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 15104aaa075a..d892cb539139 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -122,8 +122,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) } if (!zdev) return -ENODEV; - zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, - MSGTYPE50_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); zdev->ap_dev = ap_dev; zdev->online = 1; ap_device_init_reply(ap_dev, &zdev->reply); @@ -131,7 +130,6 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) rc = zcrypt_device_register(zdev); if (rc) { ap_dev->private = NULL; - zcrypt_msgtype_release(zdev->ops); zcrypt_device_free(zdev); } return rc; @@ -144,10 +142,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) static void zcrypt_cex2a_remove(struct ap_device *ap_dev) { struct zcrypt_device *zdev = ap_dev->private; - struct zcrypt_ops *zops = zdev->ops; zcrypt_device_unregister(zdev); - zcrypt_msgtype_release(zops); } int __init zcrypt_cex2a_init(void) diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index ccb2e78ebf0e..e98bdbe45d2c 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -102,8 +102,8 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) CEX4A_MAX_MOD_SIZE_2K; } zdev->short_crt = 1; - zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, - MSGTYPE50_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, + MSGTYPE50_VARIANT_DEFAULT); } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) { zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); if (!zdev) @@ -120,8 +120,8 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; zdev->short_crt = 0; - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) { zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); if (!zdev) @@ -138,8 +138,8 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; zdev->short_crt = 0; - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_EP11); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_EP11); } break; } @@ -151,7 +151,6 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) ap_dev->private = zdev; rc = zcrypt_device_register(zdev); if (rc) { - zcrypt_msgtype_release(zdev->ops); ap_dev->private = NULL; zcrypt_device_free(zdev); } @@ -165,12 +164,9 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) static void zcrypt_cex4_remove(struct ap_device *ap_dev) { struct zcrypt_device *zdev = ap_dev->private; - struct zcrypt_ops *zops; if (zdev) { - zops = zdev->ops; zcrypt_device_unregister(zdev); - zcrypt_msgtype_release(zops); } } diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index df8f0c4dacb7..8491541f72cf 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -322,11 +322,11 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) return rc; } if (rc) - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); else - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_NORNG); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_NORNG); ap_device_init_reply(ap_dev, &zdev->reply); ap_dev->private = zdev; rc = zcrypt_device_register(zdev); @@ -336,7 +336,6 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) out_free: ap_dev->private = NULL; - zcrypt_msgtype_release(zdev->ops); zcrypt_device_free(zdev); return rc; } @@ -348,10 +347,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) { struct zcrypt_device *zdev = ap_dev->private; - struct zcrypt_ops *zops = zdev->ops; zcrypt_device_unregister(zdev); - zcrypt_msgtype_release(zops); } int __init zcrypt_pcixcc_init(void) -- cgit v1.2.3 From 0db78559f965a2e652dbe8acf35333f2081bf872 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 21 Sep 2016 12:48:54 +0200 Subject: 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 --- drivers/s390/crypto/ap_asm.h | 191 +++++++++++++++++++++++++++++++++++++++++++ drivers/s390/crypto/ap_bus.c | 188 +++--------------------------------------- 2 files changed, 204 insertions(+), 175 deletions(-) create mode 100644 drivers/s390/crypto/ap_asm.h 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 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Martin Schwidefsky + * + * Adjunct processor bus inline assemblies. + */ + +#ifndef _AP_ASM_H_ +#define _AP_ASM_H_ + +#include + +/** + * ap_intructions_available() - Test if AP instructions are available. + * + * Returns 0 if the AP instructions are installed. + */ +static inline int ap_instructions_available(void) +{ + register unsigned long reg0 asm ("0") = AP_MKQID(0, 0); + register unsigned long reg1 asm ("1") = -ENODEV; + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile( + " .long 0xb2af0000\n" /* PQAP(TAPQ) */ + "0: la %1,0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc"); + return reg1; +} + +/** + * ap_tapq(): Test adjunct processor queue. + * @qid: The AP queue number + * @info: Pointer to queue descriptor + * + * Returns AP queue status structure. + */ +static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) +{ + register unsigned long reg0 asm ("0") = qid; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ + : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + if (info) + *info = reg2; + return reg1; +} + +/** + * ap_pqap_rapq(): Reset adjunct processor queue. + * @qid: The AP queue number + * + * Returns AP queue status structure. + */ +static inline struct ap_queue_status ap_rapq(ap_qid_t qid) +{ + register unsigned long reg0 asm ("0") = qid | 0x01000000UL; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile( + ".long 0xb2af0000" /* PQAP(RAPQ) */ + : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + return reg1; +} + +/** + * ap_aqic(): Enable interruption for a specific AP. + * @qid: The AP queue number + * @ind: The notification indicator byte + * + * Returns AP queue status. + */ +static inline struct ap_queue_status ap_aqic(ap_qid_t qid, void *ind) +{ + register unsigned long reg0 asm ("0") = qid | (3UL << 24); + register unsigned long reg1_in asm ("1") = (8UL << 44) | AP_ISC; + register struct ap_queue_status reg1_out asm ("1"); + register void *reg2 asm ("2") = ind; + + asm volatile( + ".long 0xb2af0000" /* PQAP(AQIC) */ + : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) + : + : "cc"); + return reg1_out; +} + +/** + * ap_qci(): Get AP configuration data + * + * Returns 0 on success, or -EOPNOTSUPP. + */ +static inline int ap_qci(void *config) +{ + register unsigned long reg0 asm ("0") = 0x04000000UL; + register unsigned long reg1 asm ("1") = -EINVAL; + register void *reg2 asm ("2") = (void *) config; + + asm volatile( + ".long 0xb2af0000\n" /* PQAP(QCI) */ + "0: la %1,0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (reg0), "+d" (reg1), "+d" (reg2) + : + : "cc"); + + return reg1; +} + +/** + * ap_nqap(): Send message to adjunct processor queue. + * @qid: The AP queue number + * @psmid: The program supplied message identifier + * @msg: The message text + * @length: The message length + * + * Returns AP queue status structure. + * Condition code 1 on NQAP can't happen because the L bit is 1. + * Condition code 2 on NQAP also means the send is incomplete, + * because a segment boundary was reached. The NQAP is repeated. + */ +static inline struct ap_queue_status ap_nqap(ap_qid_t qid, + unsigned long long psmid, + void *msg, size_t length) +{ + struct msgblock { char _[length]; }; + register unsigned long reg0 asm ("0") = qid | 0x40000000UL; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = (unsigned long) msg; + register unsigned long reg3 asm ("3") = (unsigned long) length; + register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); + register unsigned long reg5 asm ("5") = psmid & 0xffffffff; + + asm volatile ( + "0: .long 0xb2ad0042\n" /* NQAP */ + " brc 2,0b" + : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) + : "d" (reg4), "d" (reg5), "m" (*(struct msgblock *) msg) + : "cc"); + return reg1; +} + +/** + * ap_dqap(): Receive message from adjunct processor queue. + * @qid: The AP queue number + * @psmid: Pointer to program supplied message identifier + * @msg: The message text + * @length: The message length + * + * Returns AP queue status structure. + * Condition code 1 on DQAP means the receive has taken place + * but only partially. The response is incomplete, hence the + * DQAP is repeated. + * Condition code 2 on DQAP also means the receive is incomplete, + * this time because a segment boundary was reached. Again, the + * DQAP is repeated. + * Note that gpr2 is used by the DQAP instruction to keep track of + * any 'residual' length, in case the instruction gets interrupted. + * Hence it gets zeroed before the instruction. + */ +static inline struct ap_queue_status ap_dqap(ap_qid_t qid, + unsigned long long *psmid, + void *msg, size_t length) +{ + struct msgblock { char _[length]; }; + register unsigned long reg0 asm("0") = qid | 0x80000000UL; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm("2") = 0UL; + register unsigned long reg4 asm("4") = (unsigned long) msg; + register unsigned long reg5 asm("5") = (unsigned long) length; + register unsigned long reg6 asm("6") = 0UL; + register unsigned long reg7 asm("7") = 0UL; + + + asm volatile( + "0: .long 0xb2ae0064\n" /* DQAP */ + " brc 6,0b\n" + : "+d" (reg0), "=d" (reg1), "+d" (reg2), + "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), + "=m" (*(struct msgblock *) msg) : : "cc"); + *psmid = (((unsigned long long) reg6) << 32) + reg7; + return reg1; +} + +#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 @@ #include #include "ap_bus.h" +#include "ap_asm.h" /* * Module description. @@ -129,26 +130,6 @@ static inline int ap_using_interrupts(void) return ap_airq_flag; } -/** - * ap_intructions_available() - Test if AP instructions are available. - * - * Returns 0 if the AP instructions are installed. - */ -static inline int ap_instructions_available(void) -{ - register unsigned long reg0 asm ("0") = AP_MKQID(0,0); - register unsigned long reg1 asm ("1") = -ENODEV; - register unsigned long reg2 asm ("2") = 0UL; - - asm volatile( - " .long 0xb2af0000\n" /* PQAP(TAPQ) */ - "0: la %1,0\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc" ); - return reg1; -} - /** * ap_interrupts_available(): Test if AP interrupts are available. * @@ -170,19 +151,6 @@ static int ap_configuration_available(void) return test_facility(12); } -static inline struct ap_queue_status -__pqap_tapq(ap_qid_t qid, unsigned long *info) -{ - register unsigned long reg0 asm ("0") = qid; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = 0UL; - - asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ - : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); - *info = reg2; - return reg1; -} - /** * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number @@ -193,85 +161,16 @@ __pqap_tapq(ap_qid_t qid, unsigned long *info) static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, unsigned long *info) { - struct ap_queue_status aqs; - unsigned long _info; - if (test_facility(15)) qid |= 1UL << 23; /* set APFT T bit*/ - aqs = __pqap_tapq(qid, &_info); - if (info) - *info = _info; - return aqs; -} - -/** - * ap_reset_queue(): Reset adjunct processor queue. - * @qid: The AP queue number - * - * Returns AP queue status structure. - */ -static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid) -{ - register unsigned long reg0 asm ("0") = qid | 0x01000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = 0UL; - - asm volatile( - ".long 0xb2af0000" /* PQAP(RAPQ) */ - : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); - return reg1; -} - -/** - * ap_queue_interruption_control(): Enable interruption for a specific AP. - * @qid: The AP queue number - * @ind: The notification indicator byte - * - * Returns AP queue status. - */ -static inline struct ap_queue_status -ap_queue_interruption_control(ap_qid_t qid, void *ind) -{ - register unsigned long reg0 asm ("0") = qid | 0x03000000UL; - register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC; - register struct ap_queue_status reg1_out asm ("1"); - register void *reg2 asm ("2") = ind; - asm volatile( - ".long 0xb2af0000" /* PQAP(AQIC) */ - : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) - : - : "cc" ); - return reg1_out; -} - -/** - * ap_query_configuration(): Get AP configuration data - * - * Returns 0 on success, or -EOPNOTSUPP. - */ -static inline int __ap_query_configuration(void) -{ - register unsigned long reg0 asm ("0") = 0x04000000UL; - register unsigned long reg1 asm ("1") = -EINVAL; - register void *reg2 asm ("2") = (void *) ap_configuration; - - asm volatile( - ".long 0xb2af0000\n" /* PQAP(QCI) */ - "0: la %1,0\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+d" (reg0), "+d" (reg1), "+d" (reg2) - : - : "cc"); - - return reg1; + return ap_tapq(qid, info); } static inline int ap_query_configuration(void) { if (!ap_configuration) return -EOPNOTSUPP; - return __ap_query_configuration(); + return ap_qci(ap_configuration); } /** @@ -336,15 +235,15 @@ static inline int ap_test_config_domain(unsigned int domain) * @qid: The AP queue number * @ind: the notification indicator byte * - * Enables interruption on AP queue via ap_queue_interruption_control(). Based - * on the return value it waits a while and tests the AP queue if interrupts + * Enables interruption on AP queue via ap_aqic(). Based on the return + * value it waits a while and tests the AP queue if interrupts * have been switched on using ap_test_queue(). */ static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind) { struct ap_queue_status status; - status = ap_queue_interruption_control(ap_dev->qid, ind); + status = ap_aqic(ap_dev->qid, ind); switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_OTHERWISE_CHANGED: @@ -363,26 +262,6 @@ static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind) } } -static inline struct ap_queue_status -__nqap(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) -{ - typedef struct { char _[length]; } msgblock; - register unsigned long reg0 asm ("0") = qid | 0x40000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = (unsigned long) msg; - register unsigned long reg3 asm ("3") = (unsigned long) length; - register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); - register unsigned long reg5 asm ("5") = psmid & 0xffffffff; - - asm volatile ( - "0: .long 0xb2ad0042\n" /* NQAP */ - " brc 2,0b" - : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) - : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg) - : "cc"); - return reg1; -} - /** * __ap_send(): Send message to adjunct processor queue. * @qid: The AP queue number @@ -402,7 +281,7 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, { if (special == 1) qid |= 0x400000UL; - return __nqap(qid, psmid, msg, length); + return ap_nqap(qid, psmid, msg, length); } int 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) } EXPORT_SYMBOL(ap_send); -/** - * __ap_recv(): Receive message from adjunct processor queue. - * @qid: The AP queue number - * @psmid: Pointer to program supplied message identifier - * @msg: The message text - * @length: The message length - * - * Returns AP queue status structure. - * Condition code 1 on DQAP means the receive has taken place - * but only partially. The response is incomplete, hence the - * DQAP is repeated. - * Condition code 2 on DQAP also means the receive is incomplete, - * this time because a segment boundary was reached. Again, the - * DQAP is repeated. - * Note that gpr2 is used by the DQAP instruction to keep track of - * any 'residual' length, in case the instruction gets interrupted. - * Hence it gets zeroed before the instruction. - */ -static inline struct ap_queue_status -__ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) -{ - typedef struct { char _[length]; } msgblock; - register unsigned long reg0 asm("0") = qid | 0x80000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm("2") = 0UL; - register unsigned long reg4 asm("4") = (unsigned long) msg; - register unsigned long reg5 asm("5") = (unsigned long) length; - register unsigned long reg6 asm("6") = 0UL; - register unsigned long reg7 asm("7") = 0UL; - - - asm volatile( - "0: .long 0xb2ae0064\n" /* DQAP */ - " brc 6,0b\n" - : "+d" (reg0), "=d" (reg1), "+d" (reg2), - "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), - "=m" (*(msgblock *) msg) : : "cc" ); - *psmid = (((unsigned long long) reg6) << 32) + reg7; - return reg1; -} - int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) { struct ap_queue_status status; if (msg == NULL) return -EINVAL; - status = __ap_recv(qid, psmid, msg, length); + status = ap_dqap(qid, psmid, msg, length); switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -577,8 +415,8 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev) struct ap_queue_status status; struct ap_message *ap_msg; - status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid, - ap_dev->reply->message, ap_dev->reply->length); + status = ap_dqap(ap_dev->qid, &ap_dev->reply->psmid, + ap_dev->reply->message, ap_dev->reply->length); switch (status.response_code) { case AP_RESPONSE_NORMAL: atomic_dec(&ap_poll_requests); @@ -739,7 +577,7 @@ static enum ap_wait ap_sm_reset(struct ap_device *ap_dev) { struct ap_queue_status status; - status = ap_reset_queue(ap_dev->qid); + status = ap_rapq(ap_dev->qid); switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_RESET_IN_PROGRESS: @@ -1794,7 +1632,7 @@ static void ap_reset_domain(void) if (ap_domain_index == -1 || !ap_test_config_domain(ap_domain_index)) return; for (i = 0; i < AP_DEVICES; i++) - ap_reset_queue(AP_MKQID(i, ap_domain_index)); + ap_rapq(AP_MKQID(i, ap_domain_index)); } static void ap_reset_all(void) @@ -1807,7 +1645,7 @@ static void ap_reset_all(void) for (j = 0; j < AP_DEVICES; j++) { if (!ap_test_config_card_id(j)) continue; - ap_reset_queue(AP_MKQID(j, i)); + ap_rapq(AP_MKQID(j, i)); } } } -- cgit v1.2.3 From 9af3e04ee41e6841b2accb9dc96562bcf4e59916 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 21 Sep 2016 14:12:53 +0200 Subject: s390/zcrypt: get rid of ap_poll_requests The poll thread of the AP bus is burning CPU while waiting for crypto requests to complete. We can as well burn a few more cycles in the poll thread to check if there are pending requests and remove the atomic operations with the ap_poll_requests. This improves the code if the machine has adapter interrupts. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index f6de22a4f7d9..fe1cfa4b22c9 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -91,7 +91,6 @@ static DECLARE_WORK(ap_scan_work, ap_scan_bus); */ static void ap_tasklet_fn(unsigned long); static DECLARE_TASKLET(ap_tasklet, ap_tasklet_fn, 0); -static atomic_t ap_poll_requests = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread = NULL; static DEFINE_MUTEX(ap_poll_thread_mutex); @@ -419,7 +418,6 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev) ap_dev->reply->message, ap_dev->reply->length); switch (status.response_code) { case AP_RESPONSE_NORMAL: - atomic_dec(&ap_poll_requests); ap_dev->queue_count--; if (ap_dev->queue_count > 0) mod_timer(&ap_dev->timeout, @@ -436,7 +434,6 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev) if (!status.queue_empty || ap_dev->queue_count <= 0) break; /* The card shouldn't forget requests but who knows. */ - atomic_sub(ap_dev->queue_count, &ap_poll_requests); ap_dev->queue_count = 0; list_splice_init(&ap_dev->pendingq, &ap_dev->requestq); ap_dev->requestq_count += ap_dev->pendingq_count; @@ -524,7 +521,6 @@ static enum ap_wait ap_sm_write(struct ap_device *ap_dev) ap_msg->message, ap_msg->length, ap_msg->special); switch (status.response_code) { case AP_RESPONSE_NORMAL: - atomic_inc(&ap_poll_requests); ap_dev->queue_count++; if (ap_dev->queue_count == 1) mod_timer(&ap_dev->timeout, @@ -796,6 +792,27 @@ static void ap_tasklet_fn(unsigned long dummy) ap_sm_wait(wait); } +static int ap_pending_requests(void) +{ + struct ap_device *ap_dev; + int id, pending = 0; + + for (id = 0; pending == 0 && id < AP_DEVICES; id++) { + spin_lock_bh(&ap_device_list_lock); + list_for_each_entry(ap_dev, &ap_device_list, list) { + spin_lock_bh(&ap_dev->lock); + if (ap_dev->queue_count) + pending = 1; + spin_unlock_bh(&ap_dev->lock); + if (pending) + break; + } + spin_unlock_bh(&ap_device_list_lock); + } + + return pending; +} + /** * ap_poll_thread(): Thread that polls for finished requests. * @data: Unused pointer @@ -815,8 +832,7 @@ static int ap_poll_thread(void *data) while (!kthread_should_stop()) { add_wait_queue(&ap_poll_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - if (ap_suspend_flag || - atomic_read(&ap_poll_requests) <= 0) { + if (ap_suspend_flag || !ap_pending_requests()) { schedule(); try_to_freeze(); } @@ -828,7 +844,8 @@ static int ap_poll_thread(void *data) continue; } ap_tasklet_fn(0); - } while (!kthread_should_stop()); + } + return 0; } @@ -1267,9 +1284,6 @@ static int ap_device_remove(struct device *dev) spin_unlock_bh(&ap_device_list_lock); if (ap_drv->remove) ap_drv->remove(ap_dev); - spin_lock_bh(&ap_dev->lock); - atomic_sub(ap_dev->queue_count, &ap_poll_requests); - spin_unlock_bh(&ap_dev->lock); return 0; } -- cgit v1.2.3 From 34a15167739412750846d4f1a5540d9e592fd815 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:14:15 +0200 Subject: s390/zcrypt: Introduce workload balancing Crypto requests are very different in complexity and thus runtime. Also various crypto adapters are differ with regard to the execution time. Crypto requests can be balanced much better when the request type and eligible crypto adapters are rated in a more precise granularity. Therefore, request weights and adapter speed rates for dedicated requests will be introduced. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 308 ++++++++++++++++--------- drivers/s390/crypto/zcrypt_api.h | 26 ++- drivers/s390/crypto/zcrypt_cex2a.c | 12 +- drivers/s390/crypto/zcrypt_cex4.c | 36 +-- drivers/s390/crypto/zcrypt_msgtype50.c | 32 +++ drivers/s390/crypto/zcrypt_msgtype50.h | 3 + drivers/s390/crypto/zcrypt_msgtype6.c | 403 ++++++++++++++++++++++++--------- drivers/s390/crypto/zcrypt_msgtype6.h | 17 +- drivers/s390/crypto/zcrypt_pcixcc.c | 41 +++- 9 files changed, 629 insertions(+), 249 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index dc6d891a7b48..28913e540096 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -151,18 +151,16 @@ static inline int zcrypt_process_rescan(void) * Need to be called while holding the zcrypt device list lock. * Note: cards with speed_rating of 0 are kept at the end of the list. */ -static void __zcrypt_increase_preference(struct zcrypt_device *zdev) +static void __zcrypt_increase_preference(struct zcrypt_device *zdev, + unsigned int weight) { struct zcrypt_device *tmp; struct list_head *l; - if (zdev->speed_rating == 0) - return; + zdev->load -= weight; for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) { tmp = list_entry(l, struct zcrypt_device, list); - if ((tmp->request_count + 1) * tmp->speed_rating <= - (zdev->request_count + 1) * zdev->speed_rating && - tmp->speed_rating != 0) + if (tmp->load <= zdev->load) break; } if (l == zdev->list.prev) @@ -179,18 +177,16 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev) * Need to be called while holding the zcrypt device list lock. * Note: cards with speed_rating of 0 are kept at the end of the list. */ -static void __zcrypt_decrease_preference(struct zcrypt_device *zdev) +static void __zcrypt_decrease_preference(struct zcrypt_device *zdev, + unsigned int weight) { struct zcrypt_device *tmp; struct list_head *l; - if (zdev->speed_rating == 0) - return; + zdev->load += weight; for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) { tmp = list_entry(l, struct zcrypt_device, list); - if ((tmp->request_count + 1) * tmp->speed_rating > - (zdev->request_count + 1) * zdev->speed_rating || - tmp->speed_rating == 0) + if (tmp->load > zdev->load) break; } if (l == zdev->list.next) @@ -270,7 +266,7 @@ int zcrypt_device_register(struct zcrypt_device *zdev) ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid, zdev->online); list_add_tail(&zdev->list, &zcrypt_device_list); - __zcrypt_increase_preference(zdev); + __zcrypt_increase_preference(zdev, 0); /* sort devices acc. weight */ zcrypt_device_count++; spin_unlock_bh(&zcrypt_device_lock); if (zdev->ops->rng) { @@ -386,8 +382,9 @@ static int zcrypt_release(struct inode *inode, struct file *filp) */ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; int rc; + unsigned int weight, func_code, pref_weight = 0; if (mex->outputdatalength < mex->inputdatalength) return -EINVAL; @@ -398,6 +395,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) */ mex->outputdatalength = mex->inputdatalength; + rc = get_rsa_modex_fc(mex, &func_code); + if (rc) + return rc; + spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { if (!zdev->online || @@ -405,34 +406,52 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) zdev->min_mod_size > mex->inputdatalength || zdev->max_mod_size < mex->inputdatalength) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->rsa_modexpo(zdev, mex); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); + weight = zdev->speed_rating[func_code]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; } - else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + __zcrypt_decrease_preference(pref_zdev, pref_weight); + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = -ENODEV; + rc = pref_zdev->ops->rsa_modexpo(pref_zdev, mex); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + + pref_zdev->request_count--; + __zcrypt_increase_preference(pref_zdev, pref_weight); + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; unsigned long long z1, z2, z3; int rc, copied; + unsigned int weight, func_code, pref_weight = 0; if (crt->outputdatalength < crt->inputdatalength) return -EINVAL; @@ -443,6 +462,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) */ crt->outputdatalength = crt->inputdatalength; + rc = get_rsa_crt_fc(crt, &func_code); + if (rc) + return rc; + copied = 0; restart: spin_lock_bh(&zcrypt_device_lock); @@ -489,33 +512,54 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) /* The device can't handle this request. */ continue; } - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->rsa_modexpo_crt(zdev, crt); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); + + weight = zdev->speed_rating[func_code]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; } - else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + __zcrypt_decrease_preference(pref_zdev, pref_weight); + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->rsa_modexpo_crt(pref_zdev, crt); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + pref_zdev->request_count--; + __zcrypt_increase_preference(pref_zdev, pref_weight); + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static long zcrypt_send_cprb(struct ica_xcRB *xcRB) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; + unsigned int weight = 0, func_code = 0, pref_weight = 0; int rc; + struct ap_message ap_msg; + + rc = get_cprb_fc(xcRB, &ap_msg, &func_code); + if (rc) + return rc; spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { @@ -524,27 +568,42 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) (xcRB->user_defined != AUTOSELECT && AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->send_cprb(zdev, xcRB); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); + + weight = speed_idx_cca(func_code) * zdev->speed_rating[SECKEY]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; } - else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + __zcrypt_decrease_preference(pref_zdev, pref_weight); + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->send_cprb(pref_zdev, xcRB, &ap_msg); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + pref_zdev->request_count--; + __zcrypt_increase_preference(pref_zdev, pref_weight); + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } struct ep11_target_dev_list { @@ -568,7 +627,9 @@ static bool is_desired_ep11dev(unsigned int dev_qid, static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; + struct ap_message ap_msg; + unsigned int weight = 0, func_code = 0, pref_weight = 0; bool autoselect = false; int rc; struct ep11_target_dev_list ep11_dev_list = { @@ -596,6 +657,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) return -EFAULT; } + rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); + if (rc) + return rc; + spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { /* check if device is eligible */ @@ -608,58 +673,93 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) !autoselect) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->send_ep11_cprb(zdev, xcrb); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); - } else { - rc = -EAGAIN; - } - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + weight = speed_idx_ep11(func_code) * zdev->speed_rating[SECKEY]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; + } + + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->send_ep11_cprb(pref_zdev, xcrb, &ap_msg); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else { + rc = -EAGAIN; } + pref_zdev->request_count--; + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static long zcrypt_rng(char *buffer) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; + struct ap_message ap_msg; + unsigned int weight = 0, func_code = 0, pref_weight = 0; int rc; + rc = get_rng_fc(&ap_msg, &func_code); + if (rc) + return rc; + spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { if (!zdev->online || !zdev->ops->rng) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->rng(zdev, buffer); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); - } else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + + weight = zdev->speed_rating[func_code]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->rng(pref_zdev, buffer, &ap_msg); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + pref_zdev->request_count--; + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static void zcrypt_status_mask(char status[AP_DEVICES]) diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 326ecdc0417f..3d0d1e25d751 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -84,15 +84,32 @@ struct ica_z90_status { */ #define ZCRYPT_RNG_BUFFER_SIZE 4096 +/* + * Identifier for Crypto Request Performance Index + */ +enum crypto_ops { + MEX_1K = 0, + MEX_2K, + MEX_4K, + CRT_1K, + CRT_2K, + CRT_4K, + HWRNG, + SECKEY, + NUM_OPS +}; + struct zcrypt_device; struct zcrypt_ops { long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *); long (*rsa_modexpo_crt)(struct zcrypt_device *, struct ica_rsa_modexpo_crt *); - long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); - long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *); - long (*rng)(struct zcrypt_device *, char *); + long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *, + struct ap_message *); + long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *, + struct ap_message *); + long (*rng)(struct zcrypt_device *, char *, struct ap_message *); struct list_head list; /* zcrypt ops list. */ struct module *owner; int variant; @@ -112,7 +129,8 @@ struct zcrypt_device { int min_mod_size; /* Min number of bits. */ int max_mod_size; /* Max number of bits. */ int short_crt; /* Card has crt length restriction. */ - int speed_rating; /* Speed of the crypto device. */ + int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */ + int load; /* Utilization of the crypto device */ int request_count; /* # current requests. */ diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index d892cb539139..4bb13eadd0f1 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -43,9 +43,6 @@ #define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE #define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ -#define CEX2A_SPEED_RATING 970 -#define CEX3A_SPEED_RATING 900 /* Fixme: Needs finetuning */ - #define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */ #define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ @@ -87,6 +84,8 @@ static struct ap_driver zcrypt_cex2a_driver = { static int zcrypt_cex2a_probe(struct ap_device *ap_dev) { struct zcrypt_device *zdev = NULL; + int CEX2A_SPEED_IDX[] = { 800, 1000, 2000, 900, 1200, 2400, 0}; + int CEX3A_SPEED_IDX[] = { 400, 500, 1000, 450, 550, 1200, 0}; int rc = 0; switch (ap_dev->device_type) { @@ -99,7 +98,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; zdev->short_crt = 1; - zdev->speed_rating = CEX2A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX2A_SPEED_IDX, + sizeof(CEX2A_SPEED_IDX)); zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3A: @@ -117,7 +117,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; } zdev->short_crt = 1; - zdev->speed_rating = CEX3A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX3A_SPEED_IDX, + sizeof(CEX3A_SPEED_IDX)); break; } if (!zdev) @@ -125,6 +126,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); zdev->ap_dev = ap_dev; zdev->online = 1; + zdev->load = zdev->speed_rating[0]; ap_device_init_reply(ap_dev, &zdev->reply); ap_dev->private = zdev; rc = zcrypt_device_register(zdev); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index e98bdbe45d2c..ff28ad543c30 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -24,13 +24,6 @@ #define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */ #define CEX4C_MAX_MOD_SIZE 512 /* 4096 bits */ -#define CEX4A_SPEED_RATING 900 /* TODO new card, new speed rating */ -#define CEX4C_SPEED_RATING 6500 /* TODO new card, new speed rating */ -#define CEX4P_SPEED_RATING 7000 /* TODO new card, new speed rating */ -#define CEX5A_SPEED_RATING 450 /* TODO new card, new speed rating */ -#define CEX5C_SPEED_RATING 3250 /* TODO new card, new speed rating */ -#define CEX5P_SPEED_RATING 3500 /* TODO new card, new speed rating */ - #define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE @@ -71,6 +64,16 @@ static struct ap_driver zcrypt_cex4_driver = { static int zcrypt_cex4_probe(struct ap_device *ap_dev) { struct zcrypt_device *zdev = NULL; + /* + * Normalized speed ratings per crypto adapter + * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY + */ + int CEX4A_SPEED_IDX[] = { 5, 6, 59, 20, 115, 581, 0, 0}; + int CEX5A_SPEED_IDX[] = { 3, 3, 6, 8, 32, 218, 0, 0}; + int CEX4C_SPEED_IDX[] = { 24, 25, 82, 41, 138, 1111, 79, 8}; + int CEX5C_SPEED_IDX[] = { 10, 14, 23, 17, 45, 242, 63, 4}; + int CEX4P_SPEED_IDX[] = {142, 198, 1852, 203, 331, 1563, 0, 8}; + int CEX5P_SPEED_IDX[] = { 49, 67, 131, 52, 85, 287, 0, 4}; int rc = 0; switch (ap_dev->device_type) { @@ -82,10 +85,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENOMEM; if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { zdev->type_string = "CEX4A"; - zdev->speed_rating = CEX4A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX4A_SPEED_IDX, + sizeof(CEX4A_SPEED_IDX)); } else { zdev->type_string = "CEX5A"; - zdev->speed_rating = CEX5A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX5A_SPEED_IDX, + sizeof(CEX5A_SPEED_IDX)); } zdev->user_space_type = ZCRYPT_CEX3A; zdev->min_mod_size = CEX4A_MIN_MOD_SIZE; @@ -110,10 +115,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENOMEM; if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { zdev->type_string = "CEX4C"; - zdev->speed_rating = CEX4C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX4C_SPEED_IDX, + sizeof(CEX4C_SPEED_IDX)); } else { zdev->type_string = "CEX5C"; - zdev->speed_rating = CEX5C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX5C_SPEED_IDX, + sizeof(CEX5C_SPEED_IDX)); } zdev->user_space_type = ZCRYPT_CEX3C; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; @@ -128,10 +135,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENOMEM; if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { zdev->type_string = "CEX4P"; - zdev->speed_rating = CEX4P_SPEED_RATING; + memcpy(zdev->speed_rating, CEX4P_SPEED_IDX, + sizeof(CEX4P_SPEED_IDX)); } else { zdev->type_string = "CEX5P"; - zdev->speed_rating = CEX5P_SPEED_RATING; + memcpy(zdev->speed_rating, CEX5P_SPEED_IDX, + sizeof(CEX5P_SPEED_IDX)); } zdev->user_space_type = ZCRYPT_CEX4; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; @@ -147,6 +156,7 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENODEV; zdev->ap_dev = ap_dev; zdev->online = 1; + zdev->load = zdev->speed_rating[0]; ap_device_init_reply(ap_dev, &zdev->reply); ap_dev->private = zdev; rc = zcrypt_device_register(zdev); diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 7bafba83390a..fb97479af3f8 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -173,6 +173,38 @@ struct type80_hdr { unsigned char reserved3[8]; } __packed; +unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *mex, int *fcode) +{ + + if (!mex->inputdatalength) + return -EINVAL; + + if (mex->inputdatalength <= 128) /* 1024 bit */ + *fcode = MEX_1K; + else if (mex->inputdatalength <= 256) /* 2048 bit */ + *fcode = MEX_2K; + else /* 4096 bit */ + *fcode = MEX_4K; + + return 0; +} + +unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode) +{ + + if (!crt->inputdatalength) + return -EINVAL; + + if (crt->inputdatalength <= 128) /* 1024 bit */ + *fcode = CRT_1K; + else if (crt->inputdatalength <= 256) /* 2048 bit */ + *fcode = CRT_2K; + else /* 4096 bit */ + *fcode = CRT_4K; + + return 0; +} + /** * Convert a ICAMEX message to a type50 MEX message. * diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h index eeb41c0f34ae..5cc280318ee7 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.h +++ b/drivers/s390/crypto/zcrypt_msgtype50.h @@ -35,6 +35,9 @@ #define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/ +unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *, int *); +unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *, int *); + void zcrypt_msgtype50_init(void); void zcrypt_msgtype50_exit(void); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index f71949685ff5..957a88d5768b 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -149,6 +149,112 @@ static struct CPRBX static_cprbx = { .func_id = {0x54, 0x32}, }; +int speed_idx_cca(int req_type) +{ + switch (req_type) { + case 0x4142: + case 0x4149: + case 0x414D: + case 0x4341: + case 0x4344: + case 0x4354: + case 0x4358: + case 0x444B: + case 0x4558: + case 0x4643: + case 0x4651: + case 0x4C47: + case 0x4C4B: + case 0x4C51: + case 0x4F48: + case 0x504F: + case 0x5053: + case 0x5058: + case 0x5343: + case 0x5344: + case 0x5345: + case 0x5350: + return LOW; + case 0x414B: + case 0x4345: + case 0x4349: + case 0x434D: + case 0x4847: + case 0x4849: + case 0x484D: + case 0x4850: + case 0x4851: + case 0x4954: + case 0x4958: + case 0x4B43: + case 0x4B44: + case 0x4B45: + case 0x4B47: + case 0x4B48: + case 0x4B49: + case 0x4B4E: + case 0x4B50: + case 0x4B52: + case 0x4B54: + case 0x4B58: + case 0x4D50: + case 0x4D53: + case 0x4D56: + case 0x4D58: + case 0x5044: + case 0x5045: + case 0x5046: + case 0x5047: + case 0x5049: + case 0x504B: + case 0x504D: + case 0x5254: + case 0x5347: + case 0x5349: + case 0x534B: + case 0x534D: + case 0x5356: + case 0x5358: + case 0x5443: + case 0x544B: + case 0x5647: + return HIGH; + default: + return MEDIUM; + } +} + +int speed_idx_ep11(int req_type) +{ + switch (req_type) { + case 1: + case 2: + case 36: + case 37: + case 38: + case 39: + case 40: + return LOW; + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 26: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + return HIGH; + default: + return MEDIUM; + } +} + + /** * Convert a ICAMEX message to a type6 MEX message. * @@ -297,9 +403,9 @@ struct type86_fmt2_msg { struct type86_fmt2_ext fmt2; } __packed; -static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, - struct ap_message *ap_msg, - struct ica_xcRB *xcRB) +static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, + struct ica_xcRB *xcRB, + unsigned int *fcode) { static struct type6_hdr static_type6_hdrX = { .type = 0x06, @@ -379,6 +485,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); + *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1]; + if (memcmp(function_code, "US", 2) == 0) ap_msg->special = 1; else @@ -392,12 +500,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, return 0; } -static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, - struct ap_message *ap_msg, - struct ep11_urb *xcRB) +static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg, + struct ep11_urb *xcRB, + unsigned int *fcode) { - unsigned int lfmt; - static struct type6_hdr static_type6_ep11_hdr = { .type = 0x06, .rqid = {0x00, 0x01}, @@ -421,7 +527,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, unsigned char dom_tag; /* fixed value 0x4 */ unsigned char dom_len; /* fixed value 0x4 */ unsigned int dom_val; /* domain id */ - } __packed * payload_hdr; + } __packed * payload_hdr = NULL; if (CEIL4(xcRB->req_len) < xcRB->req_len) return -EINVAL; /* overflow after alignment*/ @@ -450,36 +556,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, return -EFAULT; } - /* - The target domain field within the cprb body/payload block will be - replaced by the usage domain for non-management commands only. - Therefore we check the first bit of the 'flags' parameter for - management command indication. - 0 - non management command - 1 - management command - */ - if (!((msg->cprbx.flags & 0x80) == 0x80)) { - msg->cprbx.target_