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(+) (limited to 'drivers/s390') 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(-) (limited to 'drivers/s390') 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(-) (limited to 'drivers/s390') 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 (limited to 'drivers/s390') 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(-) (limited to 'drivers/s390') 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(-) (limited to 'drivers/s390') 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_id = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); - - if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ - switch (msg->pld_lenfmt & 0x03) { - case 1: - lfmt = 2; - break; - case 2: - lfmt = 3; - break; - default: - return -EINVAL; - } - } else { - lfmt = 1; /* length format #1 */ - } - payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); - payload_hdr->dom_val = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); - } + *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF); return 0; } @@ -989,6 +1066,36 @@ out_free: return rc; } +unsigned int get_cprb_fc(struct ica_xcRB *xcRB, + struct ap_message *ap_msg, + int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_XCRB, + }; + int rc; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code); + if (rc) { + kzfree(ap_msg->message); + kzfree(ap_msg->private); + } + return rc; +} + /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a send_cprb request. @@ -997,37 +1104,55 @@ out_free: * @xcRB: pointer to the send_cprb request buffer */ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, - struct ica_xcRB *xcRB) + struct ica_xcRB *xcRB, + struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, - }; int rc; + struct response_type *rtype = (struct response_type *)(ap_msg->private); - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); - if (rc) - goto out_free; - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_xcrb(zdev, &ap_msg, xcRB); + rc = convert_response_xcrb(zdev, ap_msg, xcRB); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); -out_free: - kzfree(ap_msg.message); + ap_cancel_message(zdev->ap_dev, ap_msg); + + kzfree(ap_msg->message); + kzfree(ap_msg->private); + return rc; +} + +unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, + struct ap_message *ap_msg, + int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_EP11, + }; + int rc; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive_ep11; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + rc = xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code); + if (rc) { + kzfree(ap_msg->message); + kzfree(ap_msg->private); + } return rc; } @@ -1039,41 +1164,101 @@ out_free: * @xcRB: pointer to the ep11 user request block */ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, - struct ep11_urb *xcrb) + struct ep11_urb *xcrb, + struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_EP11, - }; int rc; + unsigned int lfmt; + struct response_type *rtype = (struct response_type *)(ap_msg->private); + struct { + struct type6_hdr hdr; + struct ep11_cprb cprbx; + unsigned char pld_tag; /* fixed value 0x30 */ + unsigned char pld_lenfmt; /* payload length format */ + } __packed * msg = ap_msg->message; + struct pld_hdr { + unsigned char func_tag; /* fixed value 0x4 */ + unsigned char func_len; /* fixed value 0x4 */ + unsigned int func_val; /* function ID */ + unsigned char dom_tag; /* fixed value 0x4 */ + unsigned char dom_len; /* fixed value 0x4 */ + unsigned int dom_val; /* domain id */ + } __packed * payload_hdr = NULL; - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive_ep11; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb); - if (rc) - goto out_free; - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + + /** + * 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_id = (unsigned int) + AP_QID_QUEUE(zdev->ap_dev->qid); + + if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ + switch (msg->pld_lenfmt & 0x03) { + case 1: + lfmt = 2; + break; + case 2: + lfmt = 3; + break; + default: + return -EINVAL; + } + } else { + lfmt = 1; /* length format #1 */ + } + payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); + payload_hdr->dom_val = (unsigned int) + AP_QID_QUEUE(zdev->ap_dev->qid); + } + + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb); + rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zdev->ap_dev, ap_msg); -out_free: - kzfree(ap_msg.message); + kzfree(ap_msg->message); + kzfree(ap_msg->private); return rc; } +unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_XCRB, + }; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + + rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE); + + *func_code = HWRNG; + return 0; +} + /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to generate random data. @@ -1081,36 +1266,36 @@ out_free: * PCIXCC/CEX2C device to the request distributor * @buffer: pointer to a memory page to return random data */ - static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, - char *buffer) + char *buffer, struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, - }; + struct { + struct type6_hdr hdr; + struct CPRBX cprbx; + char function_code[2]; + short int rule_length; + char rule[8]; + short int verb_length; + short int key_length; + } __packed * msg = ap_msg->message; + struct response_type *rtype = (struct response_type *)(ap_msg->private); int rc; - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_rng(zdev, &ap_msg, buffer); + rc = convert_response_rng(zdev, ap_msg, buffer); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); - kfree(ap_msg.message); + ap_cancel_message(zdev->ap_dev, ap_msg); + + kzfree(ap_msg->message); + kzfree(ap_msg->private); return rc; } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index 5750c4377bfa..a360dbe3c7d2 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -116,15 +116,25 @@ struct type86_fmt2_ext { unsigned int offset4; /* 0x00000000 */ } __packed; +unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, int *); +unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, int *); +unsigned int get_rng_fc(struct ap_message *, int *); + +#define LOW 10 +#define MEDIUM 100 +#define HIGH 500 + +int speed_idx_cca(int); +int speed_idx_ep11(int); + /** * Prepare a type6 CPRB message for random number generation * * @ap_dev: AP device pointer * @ap_msg: pointer to AP message */ -static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, - struct ap_message *ap_msg, - unsigned random_number_length) +static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg, + unsigned int random_number_length) { struct { struct type6_hdr hdr; @@ -156,7 +166,6 @@ static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, msg->hdr.FromCardLen2 = random_number_length, msg->cprbx = local_cprbx; msg->cprbx.rpl_datal = random_number_length, - msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); memcpy(msg->function_code, msg->hdr.function_code, 0x02); msg->rule_length = 0x0a; memcpy(msg->rule, "RANDOM ", 8); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 8491541f72cf..43de39c74944 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -46,11 +46,6 @@ #define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE #define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */ -#define PCIXCC_MCL2_SPEED_RATING 7870 -#define PCIXCC_MCL3_SPEED_RATING 7870 -#define CEX2C_SPEED_RATING 7000 -#define CEX3C_SPEED_RATING 6500 - #define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */ #define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ @@ -220,6 +215,15 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) struct type86_fmt2_ext fmt2; struct CPRBX cprbx; } __attribute__((packed)) *reply; + struct { + struct type6_hdr hdr; + struct CPRBX cprbx; + char function_code[2]; + short int rule_length; + char rule[8]; + short int verb_length; + short int key_length; + } __packed * msg; int rc, i; ap_init_message(&ap_msg); @@ -227,7 +231,11 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) if (!ap_msg.message) return -ENOMEM; - rng_type6CPRB_msgX(ap_dev, &ap_msg, 4); + rng_type6CPRB_msgX(&ap_msg, 4); + + msg = ap_msg.message; + msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); + rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message, ap_msg.length); if (rc) @@ -267,6 +275,14 @@ out_free: static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) { struct zcrypt_device *zdev; + /* + * Normalized speed ratings per crypto adapter + * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY + */ + int PCIXCC_MCL2_SPEED_IDX[] = {10, 10, 10, 10, 10, 10, 10, 10}; + int PCIXCC_MCL3_SPEED_IDX[] = { 8, 8, 8, 8, 8, 8, 8, 8}; + int CEX2C_SPEED_IDX[] = {1000, 1400, 2400, 1100, 1500, 2600, 100, 12}; + int CEX3C_SPEED_IDX[] = { 500, 700, 1400, 550, 800, 1500, 80, 10}; int rc = 0; zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); @@ -284,13 +300,15 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) zdev->user_space_type = rc; if (rc == ZCRYPT_PCIXCC_MCL2) { zdev->type_string = "PCIXCC_MCL2"; - zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING; + memcpy(zdev->speed_rating, PCIXCC_MCL2_SPEED_IDX, + sizeof(PCIXCC_MCL2_SPEED_IDX)); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; } else { zdev->type_string = "PCIXCC_MCL3"; - zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING; + memcpy(zdev->speed_rating, PCIXCC_MCL3_SPEED_IDX, + sizeof(PCIXCC_MCL3_SPEED_IDX)); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; @@ -299,7 +317,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) case AP_DEVICE_TYPE_CEX2C: zdev->user_space_type = ZCRYPT_CEX2C; zdev->type_string = "CEX2C"; - zdev->speed_rating = CEX2C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX2C_SPEED_IDX, + sizeof(CEX2C_SPEED_IDX)); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; @@ -307,7 +326,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) case AP_DEVICE_TYPE_CEX3C: zdev->user_space_type = ZCRYPT_CEX3C; zdev->type_string = "CEX3C"; - zdev->speed_rating = CEX3C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX3C_SPEED_IDX, + sizeof(CEX3C_SPEED_IDX)); zdev->min_mod_size = CEX3C_MIN_MOD_SIZE; zdev->max_mod_size = CEX3C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; @@ -315,6 +335,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) default: goto out_free; } + zdev->load = zdev->speed_rating[0]; rc = zcrypt_pcixcc_rng_supported(ap_dev); if (rc < 0) { -- cgit v1.2.3 From e28d2af43614eb86f59812e7221735fc221bbc10 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:16:03 +0200 Subject: s390/zcrypt: add multi domain support Currently the ap infrastructure only supports one domain at a time. This feature extends the generic cryptographic device driver to support multiple cryptographic domains simultaneously. There are now card and queue devices on the AP bus with independent card and queue drivers. The new /sys layout is as follows: /sys/bus/ap devices . -> ../../../devices/ap/card/. ... card -> ../../../devices/ap/card ... drivers card card -> ../../../../devices/ap/card queue . -> ../../../../devices/ap/card/. ... /sys/devices/ap card . driver -> ../../../../bus/ap/drivers/queue ... driver -> ../../../bus/ap/drivers/card ... The two digit field is the card number, the four digit field is the queue number and is the name of the device driver, e.g. "cex4". For compatability /sys/bus/ap/card for the old layout has to exist, including the attributes that used to reside there. With additional contributions from Harald Freudenberger and Martin Schwidefsky. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/Makefile | 5 +- drivers/s390/crypto/ap_bus.c | 1089 ++++++++------------------------ drivers/s390/crypto/ap_bus.h | 94 ++- drivers/s390/crypto/ap_card.c | 172 +++++ drivers/s390/crypto/ap_queue.c | 700 ++++++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 929 +++++++++++---------------- drivers/s390/crypto/zcrypt_api.h | 84 ++- drivers/s390/crypto/zcrypt_card.c | 181 ++++++ drivers/s390/crypto/zcrypt_cex2a.c | 212 +++++-- drivers/s390/crypto/zcrypt_cex4.c | 317 ++++++---- drivers/s390/crypto/zcrypt_error.h | 38 +- drivers/s390/crypto/zcrypt_msgtype50.c | 90 +-- drivers/s390/crypto/zcrypt_msgtype6.c | 253 ++++---- drivers/s390/crypto/zcrypt_msgtype6.h | 12 +- drivers/s390/crypto/zcrypt_pcixcc.c | 358 +++++------ drivers/s390/crypto/zcrypt_queue.c | 221 +++++++ include/linux/mod_devicetable.h | 3 +- 17 files changed, 2768 insertions(+), 1990 deletions(-) create mode 100644 drivers/s390/crypto/ap_card.c create mode 100644 drivers/s390/crypto/ap_queue.c create mode 100644 drivers/s390/crypto/zcrypt_card.c create mode 100644 drivers/s390/crypto/zcrypt_queue.c (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index d0549fc87247..0a7fb83f35e5 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -2,10 +2,11 @@ # S/390 crypto devices # -ap-objs := ap_bus.o +ap-objs := ap_bus.o ap_card.o ap_queue.o 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 +zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o +zcrypt-objs += 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 fe1cfa4b22c9..ac6c258300cf 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "ap_bus.h" #include "ap_asm.h" @@ -72,10 +73,12 @@ static int ap_thread_flag = 0; module_param_named(poll_thread, ap_thread_flag, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); -static struct device *ap_root_device = NULL; +static struct device *ap_root_device; + +DEFINE_SPINLOCK(ap_list_lock); +LIST_HEAD(ap_card_list); + static struct ap_config_info *ap_configuration; -static DEFINE_SPINLOCK(ap_device_list_lock); -static LIST_HEAD(ap_device_list); static bool initialised; /* @@ -129,6 +132,20 @@ static inline int ap_using_interrupts(void) return ap_airq_flag; } +/** + * ap_airq_ptr() - Get the address of the adapter interrupt indicator + * + * Returns the address of the local-summary-indicator of the adapter + * interrupt handler for AP, or NULL if adapter interrupts are not + * available. + */ +void *ap_airq_ptr(void) +{ + if (ap_using_interrupts()) + return ap_airq.lsi_ptr; + return NULL; +} + /** * ap_interrupts_available(): Test if AP interrupts are available. * @@ -229,101 +246,6 @@ static inline int ap_test_config_domain(unsigned int domain) return ap_test_config(ap_configuration->aqm, domain); } -/** - * ap_queue_enable_interruption(): Enable interruption on an AP. - * @qid: The AP queue number - * @ind: the notification indicator byte - * - * 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_aqic(ap_dev->qid, ind); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - case AP_RESPONSE_OTHERWISE_CHANGED: - return 0; - case AP_RESPONSE_Q_NOT_AVAIL: - case AP_RESPONSE_DECONFIGURED: - case AP_RESPONSE_CHECKSTOPPED: - case AP_RESPONSE_INVALID_ADDRESS: - pr_err("Registering adapter interrupts for AP %d failed\n", - AP_QID_DEVICE(ap_dev->qid)); - return -EOPNOTSUPP; - case AP_RESPONSE_RESET_IN_PROGRESS: - case AP_RESPONSE_BUSY: - default: - return -EBUSY; - } -} - -/** - * __ap_send(): 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 - * @special: Special Bit - * - * 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_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, - unsigned int special) -{ - if (special == 1) - qid |= 0x400000UL; - return ap_nqap(qid, psmid, msg, length); -} - -int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) -{ - struct ap_queue_status status; - - status = __ap_send(qid, psmid, msg, length, 0); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - return 0; - case AP_RESPONSE_Q_FULL: - case AP_RESPONSE_RESET_IN_PROGRESS: - return -EBUSY; - case AP_RESPONSE_REQ_FAC_NOT_INST: - return -EINVAL; - default: /* Device is gone. */ - return -ENODEV; - } -} -EXPORT_SYMBOL(ap_send); - -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_dqap(qid, psmid, msg, length); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - return 0; - case AP_RESPONSE_NO_PENDING_REPLY: - if (status.queue_empty) - return -ENOENT; - return -EBUSY; - case AP_RESPONSE_RESET_IN_PROGRESS: - return -EBUSY; - default: - return -ENODEV; - } -} -EXPORT_SYMBOL(ap_recv); - /** * ap_query_queue(): Check if an AP queue is available. * @qid: The AP queue number @@ -338,7 +260,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, unsigned long info; int nd; - if (!ap_test_config_card_id(AP_QID_DEVICE(qid))) + if (!ap_test_config_card_id(AP_QID_CARD(qid))) return -ENODEV; status = ap_test_queue(qid, &info); @@ -366,9 +288,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, } } -/* State machine definitions and helpers */ - -static void ap_sm_wait(enum ap_wait wait) +void ap_wait(enum ap_wait wait) { ktime_t hr_time; @@ -397,347 +317,21 @@ static void ap_sm_wait(enum ap_wait wait) } } -static enum ap_wait ap_sm_nop(struct ap_device *ap_dev) -{ - return AP_WAIT_NONE; -} - -/** - * ap_sm_recv(): Receive pending reply messages from an AP device but do - * not change the state of the device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -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_dqap(ap_dev->qid, &ap_dev->reply->psmid, - ap_dev->reply->message, ap_dev->reply->length); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - ap_dev->queue_count--; - if (ap_dev->queue_count > 0) - mod_timer(&ap_dev->timeout, - jiffies + ap_dev->drv->request_timeout); - list_for_each_entry(ap_msg, &ap_dev->pendingq, list) { - if (ap_msg->psmid != ap_dev->reply->psmid) - continue; - list_del_init(&ap_msg->list); - ap_dev->pendingq_count--; - ap_msg->receive(ap_dev, ap_msg, ap_dev->reply); - break; - } - case AP_RESPONSE_NO_PENDING_REPLY: - if (!status.queue_empty || ap_dev->queue_count <= 0) - break; - /* The card shouldn't forget requests but who knows. */ - ap_dev->queue_count = 0; - list_splice_init(&ap_dev->pendingq, &ap_dev->requestq); - ap_dev->requestq_count += ap_dev->pendingq_count; - ap_dev->pendingq_count = 0; - break; - default: - break; - } - return status; -} - -/** - * ap_sm_read(): Receive pending reply messages from an AP device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -static enum ap_wait ap_sm_read(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - - if (!ap_dev->reply) - return AP_WAIT_NONE; - status = ap_sm_recv(ap_dev); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_dev->queue_count > 0) { - ap_dev->state = AP_STATE_WORKING; - return AP_WAIT_AGAIN; - } - ap_dev->state = AP_STATE_IDLE; - return AP_WAIT_NONE; - case AP_RESPONSE_NO_PENDING_REPLY: - if (ap_dev->queue_count > 0) - return AP_WAIT_INTERRUPT; - ap_dev->state = AP_STATE_IDLE; - return AP_WAIT_NONE; - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_suspend_read(): Receive pending reply messages from an AP device - * without changing the device state in between. In suspend mode we don't - * allow sending new requests, therefore just fetch pending replies. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE or AP_WAIT_AGAIN - */ -static enum ap_wait ap_sm_suspend_read(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - - if (!ap_dev->reply) - return AP_WAIT_NONE; - status = ap_sm_recv(ap_dev); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_dev->queue_count > 0) - return AP_WAIT_AGAIN; - /* fall through */ - default: - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_write(): Send messages from the request queue to an AP device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -static enum ap_wait ap_sm_write(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - struct ap_message *ap_msg; - - if (ap_dev->requestq_count <= 0) - return AP_WAIT_NONE; - /* Start the next request on the queue. */ - ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list); - status = __ap_send(ap_dev->qid, ap_msg->psmid, - ap_msg->message, ap_msg->length, ap_msg->special); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - ap_dev->queue_count++; - if (ap_dev->queue_count == 1) - mod_timer(&ap_dev->timeout, - jiffies + ap_dev->drv->request_timeout); - list_move_tail(&ap_msg->list, &ap_dev->pendingq); - ap_dev->requestq_count--; - ap_dev->pendingq_count++; - if (ap_dev->queue_count < ap_dev->queue_depth) { - ap_dev->state = AP_STATE_WORKING; - return AP_WAIT_AGAIN; - } - /* fall through */ - case AP_RESPONSE_Q_FULL: - ap_dev->state = AP_STATE_QUEUE_FULL; - return AP_WAIT_INTERRUPT; - case AP_RESPONSE_RESET_IN_PROGRESS: - ap_dev->state = AP_STATE_RESET_WAIT; - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_MESSAGE_TOO_BIG: - case AP_RESPONSE_REQ_FAC_NOT_INST: - list_del_init(&ap_msg->list); - ap_dev->requestq_count--; - ap_msg->rc = -EINVAL; - ap_msg->receive(ap_dev, ap_msg, NULL); - return AP_WAIT_AGAIN; - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_read_write(): Send and receive messages to/from an AP device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -static enum ap_wait ap_sm_read_write(struct ap_device *ap_dev) -{ - return min(ap_sm_read(ap_dev), ap_sm_write(ap_dev)); -} - -/** - * ap_sm_reset(): Reset an AP queue. - * @qid: The AP queue number - * - * Submit the Reset command to an AP queue. - */ -static enum ap_wait ap_sm_reset(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - - status = ap_rapq(ap_dev->qid); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - case AP_RESPONSE_RESET_IN_PROGRESS: - ap_dev->state = AP_STATE_RESET_WAIT; - ap_dev->interrupt = AP_INTR_DISABLED; - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_BUSY: - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_Q_NOT_AVAIL: - case AP_RESPONSE_DECONFIGURED: - case AP_RESPONSE_CHECKSTOPPED: - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_reset_wait(): Test queue for completion of the reset operation - * @ap_dev: pointer to the AP device - * - * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. - */ -static enum ap_wait ap_sm_reset_wait(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - unsigned long info; - - if (ap_dev->queue_count > 0 && ap_dev->reply) - /* Try to read a completed message and get the status */ - status = ap_sm_recv(ap_dev); - else - /* Get the status with TAPQ */ - status = ap_test_queue(ap_dev->qid, &info); - - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_using_interrupts() && - ap_queue_enable_interruption(ap_dev, - ap_airq.lsi_ptr) == 0) - ap_dev->state = AP_STATE_SETIRQ_WAIT; - else - ap_dev->state = (ap_dev->queue_count > 0) ? - AP_STATE_WORKING : AP_STATE_IDLE; - return AP_WAIT_AGAIN; - case AP_RESPONSE_BUSY: - case AP_RESPONSE_RESET_IN_PROGRESS: - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_Q_NOT_AVAIL: - case AP_RESPONSE_DECONFIGURED: - case AP_RESPONSE_CHECKSTOPPED: - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_setirq_wait(): Test queue for completion of the irq enablement - * @ap_dev: pointer to the AP device - * - * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. - */ -static enum ap_wait ap_sm_setirq_wait(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - unsigned long info; - - if (ap_dev->queue_count > 0 && ap_dev->reply) - /* Try to read a completed message and get the status */ - status = ap_sm_recv(ap_dev); - else - /* Get the status with TAPQ */ - status = ap_test_queue(ap_dev->qid, &info); - - if (status.int_enabled == 1) { - /* Irqs are now enabled */ - ap_dev->interrupt = AP_INTR_ENABLED; - ap_dev->state = (ap_dev->queue_count > 0) ? - AP_STATE_WORKING : AP_STATE_IDLE; - } - - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_dev->queue_count > 0) - return AP_WAIT_AGAIN; - /* fallthrough */ - case AP_RESPONSE_NO_PENDING_REPLY: - return AP_WAIT_TIMEOUT; - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/* - * AP state machine jump table - */ -static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = { - [AP_STATE_RESET_START] = { - [AP_EVENT_POLL] = ap_sm_reset, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_RESET_WAIT] = { - [AP_EVENT_POLL] = ap_sm_reset_wait, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_SETIRQ_WAIT] = { - [AP_EVENT_POLL] = ap_sm_setirq_wait, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_IDLE] = { - [AP_EVENT_POLL] = ap_sm_write, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_WORKING] = { - [AP_EVENT_POLL] = ap_sm_read_write, - [AP_EVENT_TIMEOUT] = ap_sm_reset, - }, - [AP_STATE_QUEUE_FULL] = { - [AP_EVENT_POLL] = ap_sm_read, - [AP_EVENT_TIMEOUT] = ap_sm_reset, - }, - [AP_STATE_SUSPEND_WAIT] = { - [AP_EVENT_POLL] = ap_sm_suspend_read, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_BORKED] = { - [AP_EVENT_POLL] = ap_sm_nop, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, -}; - -static inline enum ap_wait ap_sm_event(struct ap_device *ap_dev, - enum ap_event event) -{ - return ap_jumptable[ap_dev->state][event](ap_dev); -} - -static inline enum ap_wait ap_sm_event_loop(struct ap_device *ap_dev, - enum ap_event event) -{ - enum ap_wait wait; - - while ((wait = ap_sm_event(ap_dev, event)) == AP_WAIT_AGAIN) - ; - return wait; -} - /** * ap_request_timeout(): Handling of request timeouts * @data: Holds the AP device. * * Handles request timeouts. */ -static void ap_request_timeout(unsigned long data) +void ap_request_timeout(unsigned long data) { - struct ap_device *ap_dev = (struct ap_device *) data; + struct ap_queue *aq = (struct ap_queue *) data; if (ap_suspend_flag) return; - spin_lock_bh(&ap_dev->lock); - ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_TIMEOUT)); - spin_unlock_bh(&ap_dev->lock); + spin_lock_bh(&aq->lock); + ap_wait(ap_sm_event(aq, AP_EVENT_TIMEOUT)); + spin_unlock_bh(&aq->lock); } /** @@ -772,7 +366,8 @@ static void ap_interrupt_handler(struct airq_struct *airq) */ static void ap_tasklet_fn(unsigned long dummy) { - struct ap_device *ap_dev; + struct ap_card *ac; + struct ap_queue *aq; enum ap_wait wait = AP_WAIT_NONE; /* Reset the indicator if interrupts are used. Thus new interrupts can @@ -782,35 +377,35 @@ static void ap_tasklet_fn(unsigned long dummy) if (ap_using_interrupts()) xchg(ap_airq.lsi_ptr, 0); - spin_lock(&ap_device_list_lock); - list_for_each_entry(ap_dev, &ap_device_list, list) { - spin_lock_bh(&ap_dev->lock); - wait = min(wait, ap_sm_event_loop(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); + spin_lock_bh(&ap_list_lock); + for_each_ap_card(ac) { + for_each_ap_queue(aq, ac) { + spin_lock_bh(&aq->lock); + wait = min(wait, ap_sm_event_loop(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); + } } - spin_unlock(&ap_device_list_lock); - ap_sm_wait(wait); + spin_unlock_bh(&ap_list_lock); + + ap_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; + struct ap_card *ac; + struct ap_queue *aq; + + spin_lock_bh(&ap_list_lock); + for_each_ap_card(ac) { + for_each_ap_queue(aq, ac) { + if (aq->queue_count == 0) + continue; + spin_unlock_bh(&ap_list_lock); + return 1; } - spin_unlock_bh(&ap_device_list_lock); } - - return pending; + spin_unlock_bh(&ap_list_lock); + return 0; } /** @@ -874,207 +469,8 @@ static void ap_poll_thread_stop(void) mutex_unlock(&ap_poll_thread_mutex); } -/** - * ap_queue_message(): Queue a request to an AP device. - * @ap_dev: The AP device to queue the message to - * @ap_msg: The message that is to be added - */ -void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) -{ - /* For asynchronous message handling a valid receive-callback - * is required. */ - BUG_ON(!ap_msg->receive); - - spin_lock_bh(&ap_dev->lock); - /* Queue the message. */ - list_add_tail(&ap_msg->list, &ap_dev->requestq); - ap_dev->requestq_count++; - ap_dev->total_request_count++; - /* Send/receive as many request from the queue as possible. */ - ap_sm_wait(ap_sm_event_loop(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_queue_message); - -/** - * ap_cancel_message(): Cancel a crypto request. - * @ap_dev: The AP device that has the message queued - * @ap_msg: The message that is to be removed - * - * Cancel a crypto request. This is done by removing the request - * from the device pending or request queue. Note that the - * request stays on the AP queue. When it finishes the message - * reply will be discarded because the psmid can't be found. - */ -void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg) -{ - struct ap_message *tmp; - - spin_lock_bh(&ap_dev->lock); - if (!list_empty(&ap_msg->list)) { - list_for_each_entry(tmp, &ap_dev->pendingq, list) - if (tmp->psmid == ap_msg->psmid) { - ap_dev->pendingq_count--; - goto found; - } - ap_dev->requestq_count--; -found: - list_del_init(&ap_msg->list); - } - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_cancel_message); - -/* - * AP device related attributes. - */ -static ssize_t ap_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type); -} - -static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); - -static ssize_t ap_raw_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - - return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->raw_hwtype); -} - -static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL); - -static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth); -} - -static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); -static ssize_t ap_request_count_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc; - - spin_lock_bh(&ap_dev->lock); - rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->total_request_count); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); - -static ssize_t ap_requestq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc; - - spin_lock_bh(&ap_dev->lock); - rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->requestq_count); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); - -static ssize_t ap_pendingq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc; - - spin_lock_bh(&ap_dev->lock); - rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->pendingq_count); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); - -static ssize_t ap_reset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc = 0; - - spin_lock_bh(&ap_dev->lock); - switch (ap_dev->state) { - case AP_STATE_RESET_START: - case AP_STATE_RESET_WAIT: - rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n"); - break; - case AP_STATE_WORKING: - case AP_STATE_QUEUE_FULL: - rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); - break; - default: - rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); - } - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL); - -static ssize_t ap_interrupt_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc = 0; - - spin_lock_bh(&ap_dev->lock); - if (ap_dev->state == AP_STATE_SETIRQ_WAIT) - rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); - else if (ap_dev->interrupt == AP_INTR_ENABLED) - rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); - else - rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL); - -static ssize_t ap_modalias_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); -} - -static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); - -static ssize_t ap_functions_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - return snprintf(buf, PAGE_SIZE, "0x%08X\n", ap_dev->functions); -} - -static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL); - -static struct attribute *ap_dev_attrs[] = { - &dev_attr_hwtype.attr, - &dev_attr_raw_hwtype.attr, - &dev_attr_depth.attr, - &dev_attr_request_count.attr, - &dev_attr_requestq_count.attr, - &dev_attr_pendingq_count.attr, - &dev_attr_reset.attr, - &dev_attr_interrupt.attr, - &dev_attr_modalias.attr, - &dev_attr_ap_functions.attr, - NULL -}; -static struct attribute_group ap_dev_attr_group = { - .attrs = ap_dev_attrs -}; +#define is_card_dev(x) ((x)->parent == ap_root_device) +#define is_queue_dev(x) ((x)->parent != ap_root_device) /** * ap_bus_match() @@ -1085,7 +481,6 @@ static struct attribute_group ap_dev_attr_group = { */ static int ap_bus_match(struct device *dev, struct device_driver *drv) { - struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = to_ap_drv(drv); struct ap_device_id *id; @@ -1094,10 +489,14 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * supported types of the device_driver. */ for (id = ap_drv->ids; id->match_flags; id++) { - if ((id->match_flags & AP_DEVICE_ID_MATCH_DEVICE_TYPE) && - (id->dev_type != ap_dev->device_type)) - continue; - return 1; + if (is_card_dev(dev) && + id->match_flags & AP_DEVICE_ID_MATCH_CARD_TYPE && + id->dev_type == to_ap_dev(dev)->device_type) + return 1; + if (is_queue_dev(dev) && + id->match_flags & AP_DEVICE_ID_MATCH_QUEUE_TYPE && + id->dev_type == to_ap_dev(dev)->device_type) + return 1; } return 0; } @@ -1133,13 +532,17 @@ static int ap_dev_suspend(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); - /* Poll on the device until all requests are finished. */ - spin_lock_bh(&ap_dev->lock); - ap_dev->state = AP_STATE_SUSPEND_WAIT; - while (ap_sm_event(ap_dev, AP_EVENT_POLL) != AP_WAIT_NONE) - ; - ap_dev->state = AP_STATE_BORKED; - spin_unlock_bh(&ap_dev->lock); + if (ap_dev->drv && ap_dev->drv->suspend) + ap_dev->drv->suspend(ap_dev); + return 0; +} + +static int ap_dev_resume(struct device *dev) +{ + struct ap_device *ap_dev = to_ap_dev(dev); + + if (ap_dev->drv && ap_dev->drv->resume) + ap_dev->drv->resume(ap_dev); return 0; } @@ -1154,9 +557,25 @@ static void ap_bus_suspend(void) tasklet_disable(&ap_tasklet); } -static int __ap_devices_unregister(struct device *dev, void *dummy) +static int __ap_card_devices_unregister(struct device *dev, void *dummy) +{ + if (is_card_dev(dev)) + device_unregister(dev); + return 0; +} + +static int __ap_queue_devices_unregister(struct device *dev, void *dummy) +{ + if (is_queue_dev(dev)) + device_unregister(dev); + return 0; +} + +static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data) { - device_unregister(dev); + if (is_queue_dev(dev) && + AP_QID_CARD(to_ap_queue(dev)->qid) == (int)(long) data) + device_unregister(dev); return 0; } @@ -1164,8 +583,13 @@ static void ap_bus_resume(void) { int rc; - /* Unconditionally remove all AP devices */ - bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_devices_unregister); + /* remove all queue devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_queue_devices_unregister); + /* remove all card devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_card_devices_unregister); + /* Reset thin interrupt setting */ if (ap_interrupts_available() && !ap_using_interrupts()) { rc = register_adapter_interrupt(&ap_airq); @@ -1207,7 +631,7 @@ static struct notifier_block ap_power_notifier = { .notifier_call = ap_power_event, }; -static SIMPLE_DEV_PM_OPS(ap_bus_pm_ops, ap_dev_suspend, NULL); +static SIMPLE_DEV_PM_OPS(ap_bus_pm_ops, ap_dev_suspend, ap_dev_resume); static struct bus_type ap_bus_type = { .name = "ap", @@ -1216,17 +640,6 @@ static struct bus_type ap_bus_type = { .pm = &ap_bus_pm_ops, }; -void ap_device_init_reply(struct ap_device *ap_dev, - struct ap_message *reply) -{ - ap_dev->reply = reply; - - spin_lock_bh(&ap_dev->lock); - ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_device_init_reply); - static int ap_device_probe(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); @@ -1240,58 +653,22 @@ static int ap_device_probe(struct device *dev) return rc; } -/** - * __ap_flush_queue(): Flush requests. - * @ap_dev: Pointer to the AP device - * - * Flush all requests from the request/pending queue of an AP device. - */ -static void __ap_flush_queue(struct ap_device *ap_dev) -{ - struct ap_message *ap_msg, *next; - - list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) { - list_del_init(&ap_msg->list); - ap_dev->pendingq_count--; - ap_msg->rc = -EAGAIN; - ap_msg->receive(ap_dev, ap_msg, NULL); - } - list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) { - list_del_init(&ap_msg->list); - ap_dev->requestq_count--; - ap_msg->rc = -EAGAIN; - ap_msg->receive(ap_dev, ap_msg, NULL); - } -} - -void ap_flush_queue(struct ap_device *ap_dev) -{ - spin_lock_bh(&ap_dev->lock); - __ap_flush_queue(ap_dev); - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_flush_queue); - static int ap_device_remove(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = ap_dev->drv; - ap_flush_queue(ap_dev); - del_timer_sync(&ap_dev->timeout); - spin_lock_bh(&ap_device_list_lock); - list_del_init(&ap_dev->list); - spin_unlock_bh(&ap_device_list_lock); + spin_lock_bh(&ap_list_lock); + if (is_card_dev(dev)) + list_del_init(&to_ap_card(dev)->list); + else + list_del_init(&to_ap_queue(dev)->list); + spin_unlock_bh(&ap_list_lock); if (ap_drv->remove) ap_drv->remove(ap_dev); return 0; } -static void ap_device_release(struct device *dev) -{ - kfree(to_ap_dev(dev)); -} - int ap_driver_register(struct ap_driver *ap_drv, struct module *owner, char *name) { @@ -1354,12 +731,7 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) { if (!ap_configuration) /* QCI not supported */ return snprintf(buf, PAGE_SIZE, "not supported\n"); - if (!test_facility(76)) - /* format 0 - 16 bit domain field */ - return snprintf(buf, PAGE_SIZE, "%08x%08x\n", - ap_configuration->adm[0], - ap_configuration->adm[1]); - /* format 1 - 256 bit domain field */ + return snprintf(buf, PAGE_SIZE, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", ap_configuration->adm[0], ap_configuration->adm[1], @@ -1371,6 +743,22 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) static BUS_ATTR(ap_control_domain_mask, 0444, ap_control_domain_mask_show, NULL); +static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) +{ + if (!ap_configuration) /* QCI not supported */ + return snprintf(buf, PAGE_SIZE, "not supported\n"); + + return snprintf(buf, PAGE_SIZE, + "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_configuration->aqm[0], ap_configuration->aqm[1], + ap_configuration->aqm[2], ap_configuration->aqm[3], + ap_configuration->aqm[4], ap_configuration->aqm[5], + ap_configuration->aqm[6], ap_configuration->aqm[7]); +} + +static BUS_ATTR(ap_usage_domain_mask, 0444, + ap_usage_domain_mask_show, NULL); + static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); @@ -1466,6 +854,7 @@ static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL); static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_ap_control_domain_mask, + &bus_attr_ap_usage_domain_mask, &bus_attr_config_time, &bus_attr_poll_thread, &bus_attr_ap_interrupts, @@ -1524,110 +913,162 @@ static int ap_select_domain(void) return -ENODEV; } -/** - * __ap_scan_bus(): Scan the AP bus. - * @dev: Pointer to device - * @data: Pointer to data - * - * Scan the AP bus for new devices. +/* + * helper function to be used with bus_find_dev + * matches for the card device with the given id */ -static int __ap_scan_bus(struct device *dev, void *data) +static int __match_card_device_with_id(struct device *dev, void *data) { - return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data; + return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; } +/* helper function to be used with bus_find_dev + * matches for the queue device with a given qid + */ +static int __match_queue_device_with_qid(struct device *dev, void *data) +{ + return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; +} + +/** + * ap_scan_bus(): Scan the AP bus for new devices + * Runs periodically, workqueue timer (ap_config_time) + */ static void ap_scan_bus(struct work_struct *unused) { - struct ap_device *ap_dev; + struct ap_queue *aq; + struct ap_card *ac; struct device *dev; ap_qid_t qid; - int queue_depth = 0, device_type = 0; - unsigned int device_functions = 0; - int rc, i, borked; + int depth = 0, type = 0; + unsigned int functions = 0; + int rc, id, dom, borked, domains; ap_query_configuration(); 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); + for (id = 0; id < AP_DEVICES; id++) { + /* check if device is registered */ dev = bus_find_device(&ap_bus_type, NULL, - (void *)(unsigned long)qid, - __ap_scan_bus); - rc = ap_query_queue(qid, &queue_depth, &device_type, - &device_functions); - if (dev) { - ap_dev = to_ap_dev(dev); - spin_lock_bh(&ap_dev->lock); - if (rc == -ENODEV) - ap_dev->state = AP_STATE_BORKED; - borked = ap_dev->state == AP_STATE_BORKED; - spin_unlock_bh(&ap_dev->lock); - if (borked) /* Remove broken device */ + (void *)(long) id, + __match_card_device_with_id); + ac = dev ? to_ap_card(dev) : NULL; + if (!ap_test_config_card_id(id)) { + if (dev) { + /* Card device has been removed from + * configuration, remove the belonging + * queue devices. + */ + bus_for_each_dev(&ap_bus_type, NULL, + (void *)(long) id, + __ap_queue_devices_with_id_unregister); + /* now remove the card device */ device_unregister(dev); - put_device(dev); - if (!borked) - continue; - } - if (rc) - continue; - ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL); - if (!ap_dev) - break; - ap_dev->qid = qid; - ap_dev->state = AP_STATE_RESET_START; - ap_dev->interrupt = AP_INTR_DISABLED; - 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); - INIT_LIST_HEAD(&ap_dev->requestq); - INIT_LIST_HEAD(&ap_dev->list); - setup_timer(&ap_dev->timeout, ap_request_timeout, - (unsigned long) ap_dev); - - ap_dev->device.bus = &ap_bus_type; - ap_dev->device.parent = ap_root_device; - rc = dev_set_name(&ap_dev->device, "card%02x", - AP_QID_DEVICE(ap_dev->qid)); - if (rc) { - kfree(ap_dev); - continue; - } - /* Add to list of devices */ - spin_lock_bh(&ap_device_list_lock); - list_add(&ap_dev->list, &ap_device_list); - spin_unlock_bh(&ap_device_list_lock); - /* Start with a device reset */ - spin_lock_bh(&ap_dev->lock); - ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); - /* Register device */ - ap_dev->device.release = ap_device_release; - rc = device_register(&ap_dev->device); - if (rc) { - spin_lock_bh(&ap_dev->lock); - list_del_init(&ap_dev->list); - spin_unlock_bh(&ap_dev->lock); - put_device(&ap_dev->device); + put_device(dev); + } continue; } - /* Add device attributes. */ - rc = sysfs_create_group(&ap_dev->device.kobj, - &ap_dev_attr_group); - if (rc) { - device_unregister(&ap_dev->device); - continue; + /* According to the configuration there should be a card + * device, so check if there is at least one valid queue + * and maybe create queue devices and the card device. + */ + domains = 0; + for (dom = 0; dom < AP_DOMAINS; dom++) { + qid = AP_MKQID(id, dom); + dev = bus_find_device(&ap_bus_type, NULL, + (void *)(long) qid, + __match_queue_device_with_qid); + aq = dev ? to_ap_queue(dev) : NULL; + if (!ap_test_config_domain(dom)) { + if (dev) { + /* Queue device exists but has been + * removed from configuration. + */ + device_unregister(dev); + put_device(dev); + } + continue; + } + rc = ap_query_queue(qid, &depth, &type, &functions); + if (dev) { + spin_lock_bh(&aq->lock); + if (rc == -ENODEV || + /* adapter reconfiguration */ + (ac && ac->functions != functions)) + aq->state = AP_STATE_BORKED; + borked = aq->state == AP_STATE_BORKED; + spin_unlock_bh(&aq->lock); + if (borked) /* Remove broken device */ + device_unregister(dev); + put_device(dev); + if (!borked) { + domains++; + continue; + } + } + if (rc) + continue; + /* new queue device needed */ + if (!ac) { + /* but first create the card device */ + ac = ap_card_create(id, depth, + type, functions); + if (!ac) + continue; + ac->ap_dev.device.bus = &ap_bus_type; + ac->ap_dev.device.parent = ap_root_device; + dev_set_name(&ac->ap_dev.device, + "card%02x", id); + /* Register card with AP bus */ + rc = device_register(&ac->ap_dev.device); + if (rc) { + put_device(&ac->ap_dev.device); + ac = NULL; + break; + } + /* get it and thus adjust reference counter */ + get_device(&ac->ap_dev.device); + /* Add card device to card list */ + spin_lock_bh(&ap_list_lock); + list_add(&ac->list, &ap_card_list); + spin_unlock_bh(&ap_list_lock); + } + /* now create the new queue device */ + aq = ap_queue_create(qid, type); + if (!aq) + continue; + aq->card = ac; + aq->ap_dev.device.bus = &ap_bus_type; + aq->ap_dev.device.parent = &ac->ap_dev.device; + dev_set_name(&aq->ap_dev.device, + "%02x.%04x", id, dom); + /* Add queue device to card queue list */ + spin_lock_bh(&ap_list_lock); + list_add(&aq->list, &ac->queues); + spin_unlock_bh(&ap_list_lock); + /* Start with a device reset */ + spin_lock_bh(&aq->lock); + ap_wait(ap_sm_event(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); + /* Register device */ + rc = device_register(&aq->ap_dev.device); + if (rc) { + spin_lock_bh(&ap_list_lock); + list_del_init(&aq->list); + spin_unlock_bh(&ap_list_lock); + put_device(&aq->ap_dev.device); + continue; + } + domains++; + } /* end domain loop */ + if (ac) { + /* remove card dev if there are no queue devices */ + if (!domains) + device_unregister(&ac->ap_dev.device); + put_device(&ac->ap_dev.device); } - } - spin_unlock_bh(&ap_domain_lock); + } /* end device loop */ out: mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); } @@ -1787,7 +1228,15 @@ void ap_module_exit(void) del_timer_sync(&ap_config_timer); hrtimer_cancel(&ap_poll_timer); tasklet_kill(&ap_tasklet); - bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_devices_unregister); + + /* first remove queue devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_queue_devices_unregister); + /* now remove the card devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_card_devices_unregister); + + /* remove bus attributes */ for (i = 0; ap_bus_attrs[i]; i++) bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); unregister_pm_notifier(&ap_power_notifier); diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index fd66d2c450d5..54b17e142792 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -27,7 +27,6 @@ #define _AP_BUS_H_ #include -#include #include #define AP_DEVICES 64 /* Number of AP devices. */ @@ -38,14 +37,17 @@ extern int ap_domain_index; +extern spinlock_t ap_list_lock; +extern struct list_head ap_card_list; + /** * The ap_qid_t identifier of an ap queue. It contains a - * 6 bit device index and a 4 bit queue index (domain). + * 6 bit card index and a 4 bit queue index (domain). */ typedef unsigned int ap_qid_t; -#define AP_MKQID(_device, _queue) (((_device) & 63) << 8 | ((_queue) & 255)) -#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63) +#define AP_MKQID(_card, _queue) (((_card) & 63) << 8 | ((_queue) & 255)) +#define AP_QID_CARD(_qid) (((_qid) >> 8) & 63) #define AP_QID_QUEUE(_qid) ((_qid) & 255) /** @@ -55,7 +57,7 @@ typedef unsigned int ap_qid_t; * @queue_full: Is 1 if the queue is full * @pad: A 4 bit pad * @int_enabled: Shows if interrupts are enabled for the AP - * @response_conde: Holds the 8 bit response code + * @response_code: Holds the 8 bit response code * @pad2: A 16 bit pad * * The ap queue status word is returned by all three AP functions @@ -167,7 +169,8 @@ struct ap_driver { int (*probe)(struct ap_device *); void (*remove)(struct ap_device *); - int request_timeout; /* request timeout in jiffies */ + void (*suspend)(struct ap_device *); + void (*resume)(struct ap_device *); }; #define to_ap_drv(x) container_of((x), struct ap_driver, driver) @@ -175,38 +178,50 @@ struct ap_driver { int ap_driver_register(struct ap_driver *, struct module *, char *); void ap_driver_unregister(struct ap_driver *); -typedef enum ap_wait (ap_func_t)(struct ap_device *ap_dev); - struct ap_device { struct device device; struct ap_driver *drv; /* Pointer to AP device driver. */ - spinlock_t lock; /* Per device lock. */ - struct list_head list; /* private list of all AP devices. */ + int device_type; /* AP device type. */ +}; - enum ap_state state; /* State of the AP device. */ +#define to_ap_dev(x) container_of((x), struct ap_device, device) - ap_qid_t qid; /* AP queue id. */ - int queue_depth; /* AP queue depth.*/ - int device_type; /* AP device type. */ +struct ap_card { + struct ap_device ap_dev; + struct list_head list; /* Private list of AP cards. */ + struct list_head queues; /* List of assoc. AP queues */ + void *private; /* ap driver private pointer. */ int raw_hwtype; /* AP raw hardware type. */ unsigned int functions; /* AP device function bitfield. */ - struct timer_list timeout; /* Timer for request timeouts. */ + int queue_depth; /* AP queue depth.*/ + int id; /* AP card number. */ +}; + +#define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) +struct ap_queue { + struct ap_device ap_dev; + struct list_head list; /* Private list of AP queues. */ + struct ap_card *card; /* Ptr to assoc. AP card. */ + spinlock_t lock; /* Per device lock. */ + void *private; /* ap driver private pointer. */ + ap_qid_t qid; /* AP queue id. */ int interrupt; /* indicate if interrupts are enabled */ int queue_count; /* # messages currently on AP queue. */ - - struct list_head pendingq; /* List of message sent to AP queue. */ + enum ap_state state; /* State of the AP device. */ int pendingq_count; /* # requests on pendingq list. */ - struct list_head requestq; /* List of message yet to be sent. */ int requestq_count; /* # requests on requestq list. */ int total_request_count; /* # requests ever for this AP device. */ - + int request_timeout; /* Request timout in jiffies. */ + struct timer_list timeout; /* Timer for request timeouts. */ + struct list_head pendingq; /* List of message sent to AP queue. */ + struct list_head requestq; /* List of message yet to be sent. */ struct ap_message *reply; /* Per device reply message. */ - - void *private; /* ap driver private pointer. */ }; -#define to_ap_dev(x) container_of((x), struct ap_device, device) +#define to_ap_queue(x) container_of((x), struct ap_queue, ap_dev.device) + +typedef enum ap_wait (ap_func_t)(struct ap_queue *queue); struct ap_message { struct list_head list; /* Request queueing. */ @@ -218,7 +233,7 @@ struct ap_message { void *private; /* ap driver private pointer. */ unsigned int special:1; /* Used for special commands. */ /* receive is called from tasklet context */ - void (*receive)(struct ap_device *, struct ap_message *, + void (*receive)(struct ap_queue *, struct ap_message *, struct ap_message *); }; @@ -233,10 +248,6 @@ struct ap_config_info { unsigned char reserved4[16]; } __packed; -#define AP_DEVICE(dt) \ - .dev_type=(dt), \ - .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, - /** * ap_init_message() - Initialize ap_message. * Initialize a message before using. Otherwise this might result in @@ -251,6 +262,12 @@ static inline void ap_init_message(struct ap_message *ap_msg) ap_msg->receive = NULL; } +#define for_each_ap_card(_ac) \ + list_for_each_entry(_ac, &ap_card_list, list) + +#define for_each_ap_queue(_aq, _ac) \ + list_for_each_entry(_aq, &(_ac)->queues, list) + /* * Note: don't use ap_send/ap_recv after using ap_queue_message * for the first time. Otherwise the ap message queue will get @@ -259,11 +276,26 @@ static inline void ap_init_message(struct ap_message *ap_msg) int ap_send(ap_qid_t, unsigned long long, void *, size_t); int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); -void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg); -void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); -void ap_flush_queue(struct ap_device *ap_dev); +enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event); +enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event); + +void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg); +void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg); +void ap_flush_queue(struct ap_queue *aq); + +void *ap_airq_ptr(void); +void ap_wait(enum ap_wait wait); +void ap_request_timeout(unsigned long data); void ap_bus_force_rescan(void); -void ap_device_init_reply(struct ap_device *ap_dev, struct ap_message *ap_msg); + +void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg); +struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type); +void ap_queue_remove(struct ap_queue *aq); +void ap_queue_suspend(struct ap_device *ap_dev); +void ap_queue_resume(struct ap_device *ap_dev); + +struct ap_card *ap_card_create(int id, int queue_depth, int device_type, + unsigned int device_functions); int ap_module_init(void); void ap_module_exit(void); diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c new file mode 100644 index 000000000000..731dc0dbfb75 --- /dev/null +++ b/drivers/s390/crypto/ap_card.c @@ -0,0 +1,172 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Martin Schwidefsky + * + * Adjunct processor bus, card related code. + */ + +#define KMSG_COMPONENT "ap" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include + +#include "ap_bus.h" +#include "ap_asm.h" + +/* + * AP card related attributes. + */ +static ssize_t ap_hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); +} + +static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); + +static ssize_t ap_raw_hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); +} + +static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL); + +static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); +} + +static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); + +static ssize_t ap_functions_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions); +} + +static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL); + +static ssize_t ap_request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + struct ap_queue *aq; + unsigned int req_cnt; + + req_cnt = 0; + spin_lock_bh(&ap_list_lock); + for_each_ap_queue(aq, ac) + req_cnt += aq->total_request_count; + spin_unlock_bh(&ap_list_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); +} + +static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); + +static ssize_t ap_requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + struct ap_queue *aq; + unsigned int reqq_cnt; + + reqq_cnt = 0; + spin_lock_bh(&ap_list_lock); + for_each_ap_queue(aq, ac) + reqq_cnt += aq->requestq_count; + spin_unlock_bh(&ap_list_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); +} + +static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); + +static ssize_t ap_pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + struct ap_queue *aq; + unsigned int penq_cnt; + + penq_cnt = 0; + spin_lock_bh(&ap_list_lock); + for_each_ap_queue(aq, ac) + penq_cnt += aq->pendingq_count; + spin_unlock_bh(&ap_list_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); +} + +static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); + +static ssize_t ap_modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); +} + +static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); + +static struct attribute *ap_card_dev_attrs[] = { + &dev_attr_hwtype.attr, + &dev_attr_raw_hwtype.attr, + &dev_attr_depth.attr, + &dev_attr_ap_functions.attr, + &dev_attr_request_count.attr, + &dev_attr_requestq_count.attr, + &dev_attr_pendingq_count.attr, + &dev_attr_modalias.attr, + NULL +}; + +static struct attribute_group ap_card_dev_attr_group = { + .attrs = ap_card_dev_attrs +}; + +static const struct attribute_group *ap_card_dev_attr_groups[] = { + &ap_card_dev_attr_group, + NULL +}; + +struct device_type ap_card_type = { + .name = "ap_card", + .groups = ap_card_dev_attr_groups, +}; + +static void ap_card_device_release(struct device *dev) +{ + kfree(to_ap_card(dev)); +} + +struct ap_card *ap_card_create(int id, int queue_depth, int device_type, + unsigned int functions) +{ + struct ap_card *ac; + + ac = kzalloc(sizeof(*ac), GFP_KERNEL); + if (!ac) + return NULL; + INIT_LIST_HEAD(&ac->queues); + ac->ap_dev.device.release = ap_card_device_release; + ac->ap_dev.device.type = &ap_card_type; + ac->ap_dev.device_type = device_type; + /* CEX6 toleration: map to CEX5 */ + if (device_type == AP_DEVICE_TYPE_CEX6) + ac->ap_dev.device_type = AP_DEVICE_TYPE_CEX5; + ac->raw_hwtype = device_type; + ac->queue_depth = queue_depth; + ac->functions = functions; + ac->id = id; + return ac; +} diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c new file mode 100644 index 000000000000..8f95a071b670 --- /dev/null +++ b/drivers/s390/crypto/ap_queue.c @@ -0,0 +1,700 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Martin Schwidefsky + * + * Adjunct processor bus, queue related code. + */ + +#define KMSG_COMPONENT "ap" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include + +#include "ap_bus.h" +#include "ap_asm.h" + +/** + * ap_queue_enable_interruption(): Enable interruption on an AP queue. + * @qid: The AP queue number + * @ind: the notification indicator byte + * + * 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_queue *aq, void *ind) +{ + struct ap_queue_status status; + + status = ap_aqic(aq->qid, ind); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + case AP_RESPONSE_OTHERWISE_CHANGED: + return 0; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_INVALID_ADDRESS: + pr_err("Registering adapter interrupts for AP device %02x.%04x failed\n", + AP_QID_CARD(aq->qid), + AP_QID_QUEUE(aq->qid)); + return -EOPNOTSUPP; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + default: + return -EBUSY; + } +} + +/** + * __ap_send(): 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 + * @special: Special Bit + * + * 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_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, + unsigned int special) +{ + if (special == 1) + qid |= 0x400000UL; + return ap_nqap(qid, psmid, msg, length); +} + +int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) +{ + struct ap_queue_status status; + + status = __ap_send(qid, psmid, msg, length, 0); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + return 0; + case AP_RESPONSE_Q_FULL: + case AP_RESPONSE_RESET_IN_PROGRESS: + return -EBUSY; + case AP_RESPONSE_REQ_FAC_NOT_INST: + return -EINVAL; + default: /* Device is gone. */ + return -ENODEV; + } +} +EXPORT_SYMBOL(ap_send); + +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_dqap(qid, psmid, msg, length); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + return 0; + case AP_RESPONSE_NO_PENDING_REPLY: + if (status.queue_empty) + return -ENOENT; + return -EBUSY; + case AP_RESPONSE_RESET_IN_PROGRESS: + return -EBUSY; + default: + return -ENODEV; + } +} +EXPORT_SYMBOL(ap_recv); + +/* State machine definitions and helpers */ + +static enum ap_wait ap_sm_nop(struct ap_queue *aq) +{ + return AP_WAIT_NONE; +} + +/** + * ap_sm_recv(): Receive pending reply messages from an AP queue but do + * not change the state of the device. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) +{ + struct ap_queue_status status; + struct ap_message *ap_msg; + + status = ap_dqap(aq->qid, &aq->reply->psmid, + aq->reply->message, aq->reply->length); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + aq->queue_count--; + if (aq->queue_count > 0) + mod_timer(&aq->timeout, + jiffies + aq->request_timeout); + list_for_each_entry(ap_msg, &aq->pendingq, list) { + if (ap_msg->psmid != aq->reply->psmid) + continue; + list_del_init(&ap_msg->list); + aq->pendingq_count--; + ap_msg->receive(aq, ap_msg, aq->reply); + break; + } + case AP_RESPONSE_NO_PENDING_REPLY: + if (!status.queue_empty || aq->queue_count <= 0) + break; + /* The card shouldn't forget requests but who knows. */ + aq->queue_count = 0; + list_splice_init(&aq->pendingq, &aq->requestq); + aq->requestq_count += aq->pendingq_count; + aq->pendingq_count = 0; + break; + default: + break; + } + return status; +} + +/** + * ap_sm_read(): Receive pending reply messages from an AP queue. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static enum ap_wait ap_sm_read(struct ap_queue *aq) +{ + struct ap_queue_status status; + + if (!aq->reply) + return AP_WAIT_NONE; + status = ap_sm_recv(aq); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (aq->queue_count > 0) { + aq->state = AP_STATE_WORKING; + return AP_WAIT_AGAIN; + } + aq->state = AP_STATE_IDLE; + return AP_WAIT_NONE; + case AP_RESPONSE_NO_PENDING_REPLY: + if (aq->queue_count > 0) + return AP_WAIT_INTERRUPT; + aq->state = AP_STATE_IDLE; + return AP_WAIT_NONE; + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_suspend_read(): Receive pending reply messages from an AP queue + * without changing the device state in between. In suspend mode we don't + * allow sending new requests, therefore just fetch pending replies. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE or AP_WAIT_AGAIN + */ +static enum ap_wait ap_sm_suspend_read(struct ap_queue *aq) +{ + struct ap_queue_status status; + + if (!aq->reply) + return AP_WAIT_NONE; + status = ap_sm_recv(aq); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (aq->queue_count > 0) + return AP_WAIT_AGAIN; + /* fall through */ + default: + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_write(): Send messages from the request queue to an AP queue. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static enum ap_wait ap_sm_write(struct ap_queue *aq) +{ + struct ap_queue_status status; + struct ap_message *ap_msg; + + if (aq->requestq_count <= 0) + return AP_WAIT_NONE; + /* Start the next request on the queue. */ + ap_msg = list_entry(aq->requestq.next, struct ap_message, list); + status = __ap_send(aq->qid, ap_msg->psmid, + ap_msg->message, ap_msg->length, ap_msg->special); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + aq->queue_count++; + if (aq->queue_count == 1) + mod_timer(&aq->timeout, jiffies + aq->request_timeout); + list_move_tail(&ap_msg->list, &aq->pendingq); + aq->requestq_count--; + aq->pendingq_count++; + if (aq->queue_count < aq->card->queue_depth) { + aq->state = AP_STATE_WORKING; + return AP_WAIT_AGAIN; + } + /* fall through */ + case AP_RESPONSE_Q_FULL: + aq->state = AP_STATE_QUEUE_FULL; + return AP_WAIT_INTERRUPT; + case AP_RESPONSE_RESET_IN_PROGRESS: + aq->state = AP_STATE_RESET_WAIT; + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_MESSAGE_TOO_BIG: + case AP_RESPONSE_REQ_FAC_NOT_INST: + list_del_init(&ap_msg->list); + aq->requestq_count--; + ap_msg->rc = -EINVAL; + ap_msg->receive(aq, ap_msg, NULL); + return AP_WAIT_AGAIN; + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_read_write(): Send and receive messages to/from an AP queue. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static enum ap_wait ap_sm_read_write(struct ap_queue *aq) +{ + return min(ap_sm_read(aq), ap_sm_write(aq)); +} + +/** + * ap_sm_reset(): Reset an AP queue. + * @qid: The AP queue number + * + * Submit the Reset command to an AP queue. + */ +static enum ap_wait ap_sm_reset(struct ap_queue *aq) +{ + struct ap_queue_status status; + + status = ap_rapq(aq->qid); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + case AP_RESPONSE_RESET_IN_PROGRESS: + aq->state = AP_STATE_RESET_WAIT; + aq->interrupt = AP_INTR_DISABLED; + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_BUSY: + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_reset_wait(): Test queue for completion of the reset operation + * @aq: pointer to the AP queue + * + * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. + */ +static enum ap_wait ap_sm_reset_wait(struct ap_queue *aq) +{ + struct ap_queue_status status; + void *lsi_ptr; + + if (aq->queue_count > 0 && aq->reply) + /* Try to read a completed message and get the status */ + status = ap_sm_recv(aq); + else + /* Get the status with TAPQ */ + status = ap_tapq(aq->qid, NULL); + + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + lsi_ptr = ap_airq_ptr(); + if (lsi_ptr && ap_queue_enable_interruption(aq, lsi_ptr) == 0) + aq->state = AP_STATE_SETIRQ_WAIT; + else + aq->state = (aq->queue_count > 0) ? + AP_STATE_WORKING : AP_STATE_IDLE; + return AP_WAIT_AGAIN; + case AP_RESPONSE_BUSY: + case AP_RESPONSE_RESET_IN_PROGRESS: + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_setirq_wait(): Test queue for completion of the irq enablement + * @aq: pointer to the AP queue + * + * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. + */ +static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq) +{ + struct ap_queue_status status; + + if (aq->queue_count > 0 && aq->reply) + /* Try to read a completed message and get the status */ + status = ap_sm_recv(aq); + else + /* Get the status with TAPQ */ + status = ap_tapq(aq->qid, NULL); + + if (status.int_enabled == 1) { + /* Irqs are now enabled */ + aq->interrupt = AP_INTR_ENABLED; + aq->state = (aq->queue_count > 0) ? + AP_STATE_WORKING : AP_STATE_IDLE; + } + + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (aq->queue_count > 0) + return AP_WAIT_AGAIN; + /* fallthrough */ + case AP_RESPONSE_NO_PENDING_REPLY: + return AP_WAIT_TIMEOUT; + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/* + * AP state machine jump table + */ +static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = { + [AP_STATE_RESET_START] = { + [AP_EVENT_POLL] = ap_sm_reset, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_RESET_WAIT] = { + [AP_EVENT_POLL] = ap_sm_reset_wait, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_SETIRQ_WAIT] = { + [AP_EVENT_POLL] = ap_sm_setirq_wait, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_IDLE] = { + [AP_EVENT_POLL] = ap_sm_write, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_WORKING] = { + [AP_EVENT_POLL] = ap_sm_read_write, + [AP_EVENT_TIMEOUT] = ap_sm_reset, + }, + [AP_STATE_QUEUE_FULL] = { + [AP_EVENT_POLL] = ap_sm_read, + [AP_EVENT_TIMEOUT] = ap_sm_reset, + }, + [AP_STATE_SUSPEND_WAIT] = { + [AP_EVENT_POLL] = ap_sm_suspend_read, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_BORKED] = { + [AP_EVENT_POLL] = ap_sm_nop, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, +}; + +enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event) +{ + return ap_jumptable[aq->state][event](aq); +} + +enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event) +{ + enum ap_wait wait; + + while ((wait = ap_sm_event(aq, event)) == AP_WAIT_AGAIN) + ; + return wait; +} + +/* + * Power management for queue devices + */ +void ap_queue_suspend(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + + /* Poll on the device until all requests are finished. */ + spin_lock_bh(&aq->lock); + aq->state = AP_STATE_SUSPEND_WAIT; + while (ap_sm_event(aq, AP_EVENT_POLL) != AP_WAIT_NONE) + ; + aq->state = AP_STATE_BORKED; + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_queue_suspend); + +void ap_queue_resume(struct ap_device *ap_dev) +{ +} +EXPORT_SYMBOL(ap_queue_resume); + +/* + * AP queue related attributes. + */ +static ssize_t ap_request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + unsigned int req_cnt; + + spin_lock_bh(&aq->lock); + req_cnt = aq->total_request_count; + spin_unlock_bh(&aq->lock); + return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); +} + +static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); + +static ssize_t ap_requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + unsigned int reqq_cnt = 0; + + spin_lock_bh(&aq->lock); + reqq_cnt = aq->requestq_count; + spin_unlock_bh(&aq->lock); + return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); +} + +static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); + +static ssize_t ap_pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + unsigned int penq_cnt = 0; + + spin_lock_bh(&aq->lock); + penq_cnt = aq->pendingq_count; + spin_unlock_bh(&aq->lock); + return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); +} + +static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); + +static ssize_t ap_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + int rc = 0; + + spin_lock_bh(&aq->lock); + switch (aq->state) { + case AP_STATE_RESET_START: + case AP_STATE_RESET_WAIT: + rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n"); + break; + case AP_STATE_WORKING: + case AP_STATE_QUEUE_FULL: + rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); + break; + default: + rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); + } + spin_unlock_bh(&aq->lock); + return rc; +} + +static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL); + +static ssize_t ap_interrupt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + int rc = 0; + + spin_lock_bh(&aq->lock); + if (aq->state == AP_STATE_SETIRQ_WAIT) + rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); + else if (aq->interrupt == AP_INTR_ENABLED) + rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); + else + rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); + spin_unlock_bh(&aq->lock); + return rc; +} + +static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL); + +static struct attribute *ap_queue_dev_attrs[] = { + &dev_attr_request_count.attr, + &dev_attr_requestq_count.attr, + &dev_attr_pendingq_count.attr, + &dev_attr_reset.attr, + &dev_attr_interrupt.attr, + NULL +}; + +static struct attribute_group ap_queue_dev_attr_group = { + .attrs = ap_queue_dev_attrs +}; + +static const struct attribute_group *ap_queue_dev_attr_groups[] = { + &ap_queue_dev_attr_group, + NULL +}; + +struct device_type ap_queue_type = { + .name = "ap_queue", + .groups = ap_queue_dev_attr_groups, +}; + +static void ap_queue_device_release(struct device *dev) +{ + kfree(to_ap_queue(dev)); +} + +struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) +{ + struct ap_queue *aq; + + aq = kzalloc(sizeof(*aq), GFP_KERNEL); + if (!aq) + return NULL; + aq->ap_dev.device.release = ap_queue_device_release; + aq->ap_dev.device.type = &ap_queue_type; + aq->ap_dev.device_type = device_type; + /* CEX6 toleration: map to CEX5 */ + if (device_type == AP_DEVICE_TYPE_CEX6) + aq->ap_dev.device_type = AP_DEVICE_TYPE_CEX5; + aq->qid = qid; + aq->state = AP_STATE_RESET_START; + aq->interrupt = AP_INTR_DISABLED; + spin_lock_init(&aq->lock); + INIT_LIST_HEAD(&aq->pendingq); + INIT_LIST_HEAD(&aq->requestq); + setup_timer(&aq->timeout, ap_request_timeout, (unsigned long) aq); + + return aq; +} + +void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *reply) +{ + aq->reply = reply; + + spin_lock_bh(&aq->lock); + ap_wait(ap_sm_event(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_queue_init_reply); + +/** + * ap_queue_message(): Queue a request to an AP device. + * @aq: The AP device to queue the message to + * @ap_msg: The message that is to be added + */ +void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg) +{ + /* For asynchronous message handling a valid receive-callback + * is required. + */ + BUG_ON(!ap_msg->receive); + + spin_lock_bh(&aq->lock); + /* Queue the message. */ + list_add_tail(&ap_msg->list, &aq->requestq); + aq->requestq_count++; + aq->total_request_count++; + /* Send/receive as many request from the queue as possible. */ + ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_queue_message); + +/** + * ap_cancel_message(): Cancel a crypto request. + * @aq: The AP device that has the message queued + * @ap_msg: The message that is to be removed + * + * Cancel a crypto request. This is done by removing the request + * from the device pending or request queue. Note that the + * request stays on the AP queue. When it finishes the message + * reply will be discarded because the psmid can't be found. + */ +void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg) +{ + struct ap_message *tmp; + + spin_lock_bh(&aq->lock); + if (!list_empty(&ap_msg->list)) { + list_for_each_entry(tmp, &aq->pendingq, list) + if (tmp->psmid == ap_msg->psmid) { + aq->pendingq_count--; + goto found; + } + aq->requestq_count--; +found: + list_del_init(&ap_msg->list); + } + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_cancel_message); + +/** + * __ap_flush_queue(): Flush requests. + * @aq: Pointer to the AP queue + * + * Flush all requests from the request/pending queue of an AP device. + */ +static void __ap_flush_queue(struct ap_queue *aq) +{ + struct ap_message *ap_msg, *next; + + list_for_each_entry_safe(ap_msg, next, &aq->pendingq, list) { + list_del_init(&ap_msg->list); + aq->pendingq_count--; + ap_msg->rc = -EAGAIN; + ap_msg->receive(aq, ap_msg, NULL); + } + list_for_each_entry_safe(ap_msg, next, &aq->requestq, list) { + list_del_init(&ap_msg->list); + aq->requestq_count--; + ap_msg->rc = -EAGAIN; + ap_msg->receive(aq, ap_msg, NULL); + } +} + +void ap_flush_queue(struct ap_queue *aq) +{ + spin_lock_bh(&aq->lock); + __ap_flush_queue(aq); + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_flush_queue); + +void ap_queue_remove(struct ap_queue *aq) +{ + ap_flush_queue(aq); + del_timer_sync(&aq->timeout); +} +EXPORT_SYMBOL(ap_queue_remove); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 28913e540096..fd0ae8cd2bee 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -59,71 +59,22 @@ static int zcrypt_hwrng_seed = 1; module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on)."); -static DEFINE_SPINLOCK(zcrypt_device_lock); -static LIST_HEAD(zcrypt_device_list); -static int zcrypt_device_count = 0; +DEFINE_SPINLOCK(zcrypt_list_lock); +LIST_HEAD(zcrypt_card_list); +int zcrypt_device_count; + static atomic_t zcrypt_open_count = ATOMIC_INIT(0); static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0); atomic_t zcrypt_rescan_req = ATOMIC_INIT(0); EXPORT_SYMBOL(zcrypt_rescan_req); -static int zcrypt_rng_device_add(void); -static void zcrypt_rng_device_remove(void); - static LIST_HEAD(zcrypt_ops_list); -static debug_info_t *zcrypt_dbf_common; -static debug_info_t *zcrypt_dbf_devices; static struct dentry *debugfs_root; - -/* - * Device attributes common for all crypto devices. - */ -static ssize_t zcrypt_type_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zcrypt_device *zdev = to_ap_dev(dev)->private; - return snprintf(buf, PAGE_SIZE, "%s\n", zdev->type_string); -} - -static DEVICE_ATTR(type, 0444, zcrypt_type_show, NULL); - -static ssize_t zcrypt_online_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zcrypt_device *zdev = to_ap_dev(dev)->private; - return snprintf(buf, PAGE_SIZE, "%d\n", zdev->online); -} - -static ssize_t zcrypt_online_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct zcrypt_device *zdev = to_ap_dev(dev)->private; - int online; - - if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) - return -EINVAL; - zdev->online = online; - ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid, - zdev->online); - if (!online) - ap_flush_queue(zdev->ap_dev); - return count; -} - -static DEVICE_ATTR(online, 0644, zcrypt_online_show, zcrypt_online_store); - -static struct attribute * zcrypt_device_attrs[] = { - &dev_attr_type.attr, - &dev_attr_online.attr, - NULL, -}; - -static struct attribute_group zcrypt_device_attr_group = { - .attrs = zcrypt_device_attrs, -}; +debug_info_t *zcrypt_dbf_common; +debug_info_t *zcrypt_dbf_devices; +debug_info_t *zcrypt_dbf_cards; /** * Process a rescan of the transport layer. @@ -143,174 +94,6 @@ static inline int zcrypt_process_rescan(void) return 0; } -/** - * __zcrypt_increase_preference(): Increase preference of a crypto device. - * @zdev: Pointer the crypto device - * - * Move the device towards the head of the device list. - * 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, - unsigned int weight) -{ - struct zcrypt_device *tmp; - struct list_head *l; - - 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->load <= zdev->load) - break; - } - if (l == zdev->list.prev) - return; - /* Move zdev behind l */ - list_move(&zdev->list, l); -} - -/** - * __zcrypt_decrease_preference(): Decrease preference of a crypto device. - * @zdev: Pointer to a crypto device. - * - * Move the device towards the tail of the device list. - * 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, - unsigned int weight) -{ - struct zcrypt_device *tmp; - struct list_head *l; - - 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->load > zdev->load) - break; - } - if (l == zdev->list.next) - return; - /* Move zdev before l */ - list_move_tail(&zdev->list, l); -} - -static void zcrypt_device_release(struct kref *kref) -{ - struct zcrypt_device *zdev = - container_of(kref, struct zcrypt_device, refcount); - zcrypt_device_free(zdev); -} - -void zcrypt_device_get(struct zcrypt_device *zdev) -{ - kref_get(&zdev->refcount); -} -EXPORT_SYMBOL(zcrypt_device_get); - -int zcrypt_device_put(struct zcrypt_device *zdev) -{ - return kref_put(&zdev->refcount, zcrypt_device_release); -} -EXPORT_SYMBOL(zcrypt_device_put); - -struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size) -{ - struct zcrypt_device *zdev; - - zdev = kzalloc(sizeof(struct zcrypt_device), GFP_KERNEL); - if (!zdev) - return NULL; - zdev->reply.message = kmalloc(max_response_size, GFP_KERNEL); - if (!zdev->reply.message) - goto out_free; - zdev->reply.length = max_response_size; - spin_lock_init(&zdev->lock); - INIT_LIST_HEAD(&zdev->list); - zdev->dbf_area = zcrypt_dbf_devices; - return zdev; - -out_free: - kfree(zdev); - return NULL; -} -EXPORT_SYMBOL(zcrypt_device_alloc); - -void zcrypt_device_free(struct zcrypt_device *zdev) -{ - kfree(zdev->reply.message); - kfree(zdev); -} -EXPORT_SYMBOL(zcrypt_device_free); - -/** - * zcrypt_device_register() - Register a crypto device. - * @zdev: Pointer to a crypto device - * - * Register a crypto device. Returns 0 if successful. - */ -int zcrypt_device_register(struct zcrypt_device *zdev) -{ - int rc; - - if (!zdev->ops) - return -ENODEV; - rc = sysfs_create_group(&zdev->ap_dev->device.kobj, - &zcrypt_device_attr_group); - if (rc) - goto out; - get_device(&zdev->ap_dev->device); - kref_init(&zdev->refcount); - spin_lock_bh(&zcrypt_device_lock); - zdev->online = 1; /* New devices are online by default. */ - 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, 0); /* sort devices acc. weight */ - zcrypt_device_count++; - spin_unlock_bh(&zcrypt_device_lock); - if (zdev->ops->rng) { - rc = zcrypt_rng_device_add(); - if (rc) - goto out_unregister; - } - return 0; - -out_unregister: - spin_lock_bh(&zcrypt_device_lock); - zcrypt_device_count--; - list_del_init(&zdev->list); - spin_unlock_bh(&zcrypt_device_lock); - sysfs_remove_group(&zdev->ap_dev->device.kobj, - &zcrypt_device_attr_group); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); -out: - return rc; -} -EXPORT_SYMBOL(zcrypt_device_register); - -/** - * zcrypt_device_unregister(): Unregister a crypto device. - * @zdev: Pointer to crypto device - * - * Unregister a crypto device. - */ -void zcrypt_device_unregister(struct zcrypt_device *zdev) -{ - if (zdev->ops->rng) - zcrypt_rng_device_remove(); - spin_lock_bh(&zcrypt_device_lock); - zcrypt_device_count--; - list_del_init(&zdev->list); - spin_unlock_bh(&zcrypt_device_lock); - sysfs_remove_group(&zdev->ap_dev->device.kobj, - &zcrypt_device_attr_group); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); -} -EXPORT_SYMBOL(zcrypt_device_unregister); - void zcrypt_msgtype_register(struct zcrypt_ops *zops) { list_add_tail(&zops->list, &zcrypt_ops_list); @@ -377,14 +160,44 @@ static int zcrypt_release(struct inode *inode, struct file *filp) return 0; } +static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc, + struct zcrypt_queue *zq, + unsigned int weight) +{ + if (!zq || !try_module_get(zq->queue->ap_dev.drv->driver.owner)) + return NULL; + zcrypt_queue_get(zq); + get_device(&zq->queue->ap_dev.device); + atomic_add(weight, &zc->load); + atomic_add(weight, &zq->load); + zq->request_count++; + return zq; +} + +static inline void zcrypt_drop_queue(struct zcrypt_card *zc, + struct zcrypt_queue *zq, + unsigned int weight) +{ + struct module *mod = zq->queue->ap_dev.drv->driver.owner; + + zq->request_count--; + atomic_sub(weight, &zc->load); + atomic_sub(weight, &zq->load); + put_device(&zq->queue->ap_dev.device); + zcrypt_queue_put(zq); + module_put(mod); +} + /* * zcrypt ioctls. */ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) { - struct zcrypt_device *zdev, *pref_zdev = NULL; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + unsigned int weight, pref_weight; + unsigned int func_code; int rc; - unsigned int weight, func_code, pref_weight = 0; if (mex->outputdatalength < mex->inputdatalength) return -EINVAL; @@ -399,59 +212,56 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) if (rc) return rc; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - if (!zdev->online || - !zdev->ops->rsa_modexpo || - zdev->min_mod_size > mex->inputdatalength || - zdev->max_mod_size < mex->inputdatalength) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online accelarator and CCA cards */ + if (!zc->online || !(zc->card->functions & 0x18000000)) continue; - weight = zdev->speed_rating[func_code]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* Check for size limits */ + if (zc->min_mod_size > mex->inputdatalength || + zc->max_mod_size < mex->inputdatalength) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = zc->speed_rating[func_code]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; + pref_weight = weight; } - if ((pref_zdev->load + pref_weight) <= zdev->load) - break; /* Load on remaining devices too high - abort */ } + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); - if (!pref_zdev) { - spin_unlock_bh(&zcrypt_device_lock); + if (!pref_zq) 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); + rc = pref_zq->ops->rsa_modexpo(pref_zq, mex); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + return rc; } static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) { - struct zcrypt_device *zdev, *pref_zdev = NULL; - unsigned long long z1, z2, z3; - int rc, copied; - unsigned int weight, func_code, pref_weight = 0; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + unsigned int weight, pref_weight; + unsigned int func_code; + int rc; if (crt->outputdatalength < crt->inputdatalength) return -EINVAL; @@ -466,385 +276,388 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) if (rc) return rc; - copied = 0; - restart: - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - if (!zdev->online || - !zdev->ops->rsa_modexpo_crt || - zdev->min_mod_size > crt->inputdatalength || - zdev->max_mod_size < crt->inputdatalength) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online accelarator and CCA cards */ + if (!zc->online || !(zc->card->functions & 0x18000000)) continue; - if (zdev->short_crt && crt->inputdatalength > 240) { - /* - * Check inputdata for leading zeros for cards - * that can't handle np_prime, bp_key, or - * u_mult_inv > 128 bytes. - */ - if (copied == 0) { - unsigned int len; - spin_unlock_bh(&zcrypt_device_lock); - /* len is max 256 / 2 - 120 = 8 - * For bigger device just assume len of leading - * 0s is 8 as stated in the requirements for - * ica_rsa_modexpo_crt struct in zcrypt.h. - */ - if (crt->inputdatalength <= 256) - len = crt->inputdatalength / 2 - 120; - else - len = 8; - if (len > sizeof(z1)) - return -EFAULT; - z1 = z2 = z3 = 0; - if (copy_from_user(&z1, crt->np_prime, len) || - copy_from_user(&z2, crt->bp_key, len) || - copy_from_user(&z3, crt->u_mult_inv, len)) - return -EFAULT; - z1 = z2 = z3 = 0; - copied = 1; - /* - * We have to restart device lookup - - * the device list may have changed by now. - */ - goto restart; - } - if (z1 != 0ULL || z2 != 0ULL || z3 != 0ULL) - /* The device can't handle this request. */ - continue; - } - - weight = zdev->speed_rating[func_code]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* Check for size limits */ + if (zc->min_mod_size > crt->inputdatalength || + zc->max_mod_size < crt->inputdatalength) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = zc->speed_rating[func_code]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; + pref_weight = weight; } - 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); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + + if (!pref_zq) 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); + + rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + return rc; } static long zcrypt_send_cprb(struct ica_xcRB *xcRB) { - struct zcrypt_device *zdev, *pref_zdev = NULL; - unsigned int weight = 0, func_code = 0, pref_weight = 0; - int rc; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; struct ap_message ap_msg; + unsigned int weight, pref_weight; + unsigned int func_code; + unsigned short *domain; + int rc; - rc = get_cprb_fc(xcRB, &ap_msg, &func_code); + rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); if (rc) return rc; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - if (!zdev->online || !zdev->ops->send_cprb || - (zdev->ops->variant == MSGTYPE06_VARIANT_EP11) || - (xcRB->user_defined != AUTOSELECT && - AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online CCA cards */ + if (!zc->online || !(zc->card->functions & 0x10000000)) continue; - - weight = speed_idx_cca(func_code) * zdev->speed_rating[SECKEY]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* Check for user selected CCA card */ + if (xcRB->user_defined != AUTOSELECT && + xcRB->user_defined != zc->card->id) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online || + ((*domain != (unsigned short) AUTOSELECT) && + (*domain != AP_QID_QUEUE(zq->queue->qid)))) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; + pref_weight = weight; } - 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); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + + if (!pref_zq) 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); + + /* in case of auto select, provide the correct domain */ + if (*domain == (unsigned short) AUTOSELECT) + *domain = AP_QID_QUEUE(pref_zq->queue->qid); + + rc = pref_zq->ops->send_cprb(pref_zq, xcRB, &ap_msg); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); return rc; } -struct ep11_target_dev_list { - unsigned short targets_num; - struct ep11_target_dev *targets; -}; - -static bool is_desired_ep11dev(unsigned int dev_qid, - struct ep11_target_dev_list dev_list) +static bool is_desired_ep11_card(unsigned int dev_id, + unsigned short target_num, + struct ep11_target_dev *targets) { - int n; + while (target_num-- > 0) { + if (dev_id == targets->ap_id) + return true; + targets++; + } + return false; +} - for (n = 0; n < dev_list.targets_num; n++, dev_list.targets++) { - if ((AP_QID_DEVICE(dev_qid) == dev_list.targets->ap_id) && - (AP_QID_QUEUE(dev_qid) == dev_list.targets->dom_id)) { +static bool is_desired_ep11_queue(unsigned int dev_qid, + unsigned short target_num, + struct ep11_target_dev *targets) +{ + while (target_num-- > 0) { + if (AP_MKQID(targets->ap_id, targets->dom_id) == dev_qid) return true; - } + targets++; } return false; } static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) { - struct zcrypt_device *zdev, *pref_zdev = NULL; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + struct ep11_target_dev *targets; + unsigned short target_num; + unsigned int weight, pref_weight; + unsigned int func_code; 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 = { - .targets_num = 0x00, - .targets = NULL, - }; - ep11_dev_list.targets_num = (unsigned short) xcrb->targets_num; + target_num = (unsigned short) xcrb->targets_num; /* empty list indicates autoselect (all available targets) */ - if (ep11_dev_list.targets_num == 0) - autoselect = true; - else { - ep11_dev_list.targets = kcalloc((unsigned short) - xcrb->targets_num, - sizeof(struct ep11_target_dev), - GFP_KERNEL); - if (!ep11_dev_list.targets) + targets = NULL; + if (target_num != 0) { + struct ep11_target_dev __user *uptr; + + targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL); + if (!targets) return -ENOMEM; - if (copy_from_user(ep11_dev_list.targets, - (struct ep11_target_dev __force __user *) - xcrb->targets, xcrb->targets_num * - sizeof(struct ep11_target_dev))) + uptr = (struct ep11_target_dev __force __user *) xcrb->targets; + if (copy_from_user(targets, uptr, + target_num * sizeof(*targets))) return -EFAULT; } rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); if (rc) - return rc; + goto out_free; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - /* check if device is eligible */ - if (!zdev->online || - zdev->ops->variant != MSGTYPE06_VARIANT_EP11) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online EP11 cards */ + if (!zc->online || !(zc->card->functions & 0x04000000)) continue; - - /* check if device is selected as valid target */ - if (!is_desired_ep11dev(zdev->ap_dev->qid, ep11_dev_list) && - !autoselect) + /* Check for user selected EP11 card */ + if (targets && + !is_desired_ep11_card(zc->card->id, target_num, targets)) continue; - - weight = speed_idx_ep11(func_code) * zdev->speed_rating[SECKEY]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online || + (targets && + !is_desired_ep11_queue(zq->queue->qid, + target_num, targets))) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; 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 -ENODEV; } + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); - 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; + if (!pref_zq) { + rc = -ENODEV; + goto out_free; } - pref_zdev->request_count--; - put_device(&pref_zdev->ap_dev->device); - zcrypt_device_put(pref_zdev); - spin_unlock_bh(&zcrypt_device_lock); + + rc = pref_zq->ops->send_ep11_cprb(pref_zq, xcrb, &ap_msg); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + +out_free: + kfree(targets); return rc; } static long zcrypt_rng(char *buffer) { - struct zcrypt_device *zdev, *pref_zdev = NULL; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + unsigned int weight, pref_weight; + unsigned int func_code; struct ap_message ap_msg; - unsigned int weight = 0, func_code = 0, pref_weight = 0; + unsigned int domain; int rc; - rc = get_rng_fc(&ap_msg, &func_code); + rc = get_rng_fc(&ap_msg, &func_code, &domain); 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) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online CCA cards */ + if (!zc->online || !(zc->card->functions & 0x10000000)) continue; - - weight = zdev->speed_rating[func_code]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = zc->speed_rating[func_code]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; 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); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + + if (!pref_zq) 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); + rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); return rc; } static void zcrypt_status_mask(char status[AP_DEVICES]) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; memset(status, 0, sizeof(char) * AP_DEVICES); - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - status[AP_QID_DEVICE(zdev->ap_dev->qid)] = - zdev->online ? zdev->user_space_type : 0x0d; - spin_unlock_bh(&zcrypt_device_lock); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + status[AP_QID_CARD(zq->queue->qid)] = + zc->online ? zc->user_space_type : 0x0d; + } + } + spin_unlock(&zcrypt_list_lock); } static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES]) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; memset(qdepth, 0, sizeof(char) * AP_DEVICES); - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] = - zdev->ap_dev->pendingq_count + - zdev->ap_dev->requestq_count; - spin_unlock(&zdev->ap_dev->lock); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + qdepth[AP_QID_CARD(zq->queue->qid)] = + zq->queue->pendingq_count + + zq->queue->requestq_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); } static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES]) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; memset(reqcnt, 0, sizeof(int) * AP_DEVICES); - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] = - zdev->ap_dev->total_request_count; - spin_unlock(&zdev->ap_dev->lock); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + reqcnt[AP_QID_CARD(zq->queue->qid)] = + zq->queue->total_request_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); } static int zcrypt_pendingq_count(void) { - struct zcrypt_device *zdev; - int pendingq_count = 0; - - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - pendingq_count += zdev->ap_dev->pendingq_count; - spin_unlock(&zdev->ap_dev->lock); + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + int pendingq_count; + + pendingq_count = 0; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + pendingq_count += zq->queue->pendingq_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); return pendingq_count; } static int zcrypt_requestq_count(void) { - struct zcrypt_device *zdev; - int requestq_count = 0; - - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - requestq_count += zdev->ap_dev->requestq_count; - spin_unlock(&zdev->ap_dev->lock); + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + int requestq_count; + + requestq_count = 0; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + requestq_count += zq->queue->requestq_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); return requestq_count; } static int zcrypt_count_type(int type) { - struct zcrypt_device *zdev; - int device_count = 0; - - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - if (zdev->user_space_type == type) + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + int device_count; + + device_count = 0; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + if (zc->card->id != type) + continue; + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; device_count++; - spin_unlock_bh(&zcrypt_device_lock); + } + } + spin_unlock(&zcrypt_list_lock); return device_count; } @@ -1313,29 +1126,36 @@ static int zcrypt_proc_open(struct inode *inode, struct file *file) static void zcrypt_disable_card(int index) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { - zdev->online = 0; - ap_flush_queue(zdev->ap_dev); - break; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + zq->online = 0; + ap_flush_queue(zq->queue); } - spin_unlock_bh(&zcrypt_device_lock); + } + spin_unlock(&zcrypt_list_lock); } static void zcrypt_enable_card(int index) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { - zdev->online = 1; - break; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + zq->online = 1; + ap_flush_queue(zq->queue); } - spin_unlock_bh(&zcrypt_device_lock); + } + spin_unlock(&zcrypt_list_lock); } static ssize_t zcrypt_proc_write(struct file *file, const char __user *buffer, @@ -1433,7 +1253,7 @@ static struct hwrng zcrypt_rng_dev = { .quality = 990, }; -static int zcrypt_rng_device_add(void) +int zcrypt_rng_device_add(void) { int rc = 0; @@ -1463,7 +1283,7 @@ out: return rc; } -static void zcrypt_rng_device_remove(void) +void zcrypt_rng_device_remove(void) { mutex_lock(&zcrypt_rng_mutex); zcrypt_rng_device_count--; @@ -1486,6 +1306,10 @@ int __init zcrypt_debug_init(void) debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view); debug_set_level(zcrypt_dbf_devices, DBF_ERR); + zcrypt_dbf_cards = debug_register("zcrypt_cards", 1, 1, 16); + debug_register_view(zcrypt_dbf_cards, &debug_hex_ascii_view); + debug_set_level(zcrypt_dbf_cards, DBF_ERR); + return 0; } @@ -1517,7 +1341,8 @@ int __init zcrypt_api_init(void) goto out; /* Set up the proc file system */ - zcrypt_entry = proc_create("driver/z90crypt", 0644, NULL, &zcrypt_proc_fops); + zcrypt_entry = proc_create("driver/z90crypt", 0644, NULL, + &zcrypt_proc_fops); if (!zcrypt_entry) { rc = -ENOMEM; goto out_misc; diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 3d0d1e25d751..4fb892b99f41 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -88,7 +88,7 @@ struct ica_z90_status { * Identifier for Crypto Request Performance Index */ enum crypto_ops { - MEX_1K = 0, + MEX_1K, MEX_2K, MEX_4K, CRT_1K, @@ -99,43 +99,56 @@ enum crypto_ops { NUM_OPS }; -struct zcrypt_device; +struct zcrypt_queue; struct zcrypt_ops { - long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *); - long (*rsa_modexpo_crt)(struct zcrypt_device *, + long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *); + long (*rsa_modexpo_crt)(struct zcrypt_queue *, struct ica_rsa_modexpo_crt *); - long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *, + long (*send_cprb)(struct zcrypt_queue *, struct ica_xcRB *, struct ap_message *); - long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *, + long (*send_ep11_cprb)(struct zcrypt_queue *, struct ep11_urb *, struct ap_message *); - long (*rng)(struct zcrypt_device *, char *, struct ap_message *); + long (*rng)(struct zcrypt_queue *, char *, struct ap_message *); struct list_head list; /* zcrypt ops list. */ struct module *owner; int variant; char name[128]; }; -struct zcrypt_device { +struct zcrypt_card { struct list_head list; /* Device list. */ - spinlock_t lock; /* Per device lock. */ + struct list_head zqueues; /* List of zcrypt queues */ struct kref refcount; /* device refcounting */ - struct ap_device *ap_dev; /* The "real" ap device. */ - struct zcrypt_ops *ops; /* Crypto operations. */ + struct ap_card *card; /* The "real" ap card device. */ int online; /* User online/offline */ int user_space_type; /* User space device id. */ char *type_string; /* User space device name. */ 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 max_exp_bit_length; int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */ - int load; /* Utilization of the crypto device */ + atomic_t load; /* Utilization of the crypto device */ + + int request_count; /* # current requests. */ + + debug_info_t *dbf_area; /* debugging */ +}; + +struct zcrypt_queue { + struct list_head list; /* Device list. */ + struct kref refcount; /* device refcounting */ + struct zcrypt_card *zcard; + struct zcrypt_ops *ops; /* Crypto operations. */ + struct ap_queue *queue; /* The "real" ap queue device. */ + int online; /* User online/offline */ + + atomic_t load; /* Utilization of the crypto device */ int request_count; /* # current requests. */ struct ap_message reply; /* Per-device reply structure. */ - int max_exp_bit_length; debug_info_t *dbf_area; /* debugging */ }; @@ -143,12 +156,43 @@ struct zcrypt_device { /* transport layer rescanning */ extern atomic_t zcrypt_rescan_req; -struct zcrypt_device *zcrypt_device_alloc(size_t); -void zcrypt_device_free(struct zcrypt_device *); -void zcrypt_device_get(struct zcrypt_device *); -int zcrypt_device_put(struct zcrypt_device *); -int zcrypt_device_register(struct zcrypt_device *); -void zcrypt_device_unregister(struct zcrypt_device *); +extern spinlock_t zcrypt_list_lock; +extern int zcrypt_device_count; +extern struct list_head zcrypt_card_list; + +extern debug_info_t *zcrypt_dbf_common; +extern debug_info_t *zcrypt_dbf_devices; +extern debug_info_t *zcrypt_dbf_cards; + +#define for_each_zcrypt_card(_zc) \ + list_for_each_entry(_zc, &zcrypt_card_list, list) + +#define for_each_zcrypt_queue(_zq, _zc) \ + list_for_each_entry(_zq, &(_zc)->zqueues, list) + +struct zcrypt_card *zcrypt_card_alloc(void); +void zcrypt_card_free(struct zcrypt_card *); +void zcrypt_card_get(struct zcrypt_card *); +int zcrypt_card_put(struct zcrypt_card *); +int zcrypt_card_register(struct zcrypt_card *); +void zcrypt_card_unregister(struct zcrypt_card *); +struct zcrypt_card *zcrypt_card_get_best(unsigned int *, + unsigned int, unsigned int); +void zcrypt_card_put_best(struct zcrypt_card *, unsigned int); + +struct zcrypt_queue *zcrypt_queue_alloc(size_t); +void zcrypt_queue_free(struct zcrypt_queue *); +void zcrypt_queue_get(struct zcrypt_queue *); +int zcrypt_queue_put(struct zcrypt_queue *); +int zcrypt_queue_register(struct zcrypt_queue *); +void zcrypt_queue_unregister(struct zcrypt_queue *); +void zcrypt_queue_force_online(struct zcrypt_queue *, int); +struct zcrypt_queue *zcrypt_queue_get_best(unsigned int, unsigned int); +void zcrypt_queue_put_best(struct zcrypt_queue *, unsigned int); + +int zcrypt_rng_device_add(void); +void zcrypt_rng_device_remove(void); + void zcrypt_msgtype_register(struct zcrypt_ops *); void zcrypt_msgtype_unregister(struct zcrypt_ops *); struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int); diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c new file mode 100644 index 000000000000..57873d775e95 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_card.c @@ -0,0 +1,181 @@ +/* + * zcrypt 2.1.0 + * + * Copyright IBM Corp. 2001, 2012 + * Author(s): Robert Burroughs + * Eric Rossman (edrossma@us.ibm.com) + * Cornelia Huck + * + * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) + * Major cleanup & driver split: Martin Schwidefsky + * Ralph Wuerthner + * MSGTYPE restruct: Holger Dengler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zcrypt_debug.h" +#include "zcrypt_api.h" + +#include "zcrypt_msgtype6.h" +#include "zcrypt_msgtype50.h" + +/* + * Device attributes common for all crypto card devices. + */ + +static ssize_t zcrypt_card_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct zcrypt_card *zc = to_ap_card(dev)->private; + + return snprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); +} + +static DEVICE_ATTR(type, 0444, zcrypt_card_type_show, NULL); + +static ssize_t zcrypt_card_online_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zcrypt_card *zc = to_ap_card(dev)->private; + + return snprintf(buf, PAGE_SIZE, "%d\n", zc->online); +} + +static ssize_t zcrypt_card_online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zcrypt_card *zc = to_ap_card(dev)->private; + struct zcrypt_queue *zq; + int online, id; + + if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) + return -EINVAL; + + zc->online = online; + id = zc->card->id; + ZCRYPT_DBF_DEV(DBF_INFO, zc, "card%02xo%dman", id, online); + spin_lock(&zcrypt_list_lock); + list_for_each_entry(zq, &zc->zqueues, list) + zcrypt_queue_force_online(zq, online); + spin_unlock(&zcrypt_list_lock); + return count; +} + +static DEVICE_ATTR(online, 0644, zcrypt_card_online_show, + zcrypt_card_online_store); + +static struct attribute *zcrypt_card_attrs[] = { + &dev_attr_type.attr, + &dev_attr_online.attr, + NULL, +}; + +static struct attribute_group zcrypt_card_attr_group = { + .attrs = zcrypt_card_attrs, +}; + +struct zcrypt_card *zcrypt_card_alloc(void) +{ + struct zcrypt_card *zc; + + zc = kzalloc(sizeof(struct zcrypt_card), GFP_KERNEL); + if (!zc) + return NULL; + INIT_LIST_HEAD(&zc->list); + INIT_LIST_HEAD(&zc->zqueues); + zc->dbf_area = zcrypt_dbf_cards; + kref_init(&zc->refcount); + return zc; +} +EXPORT_SYMBOL(zcrypt_card_alloc); + +void zcrypt_card_free(struct zcrypt_card *zc) +{ + kfree(zc); +} +EXPORT_SYMBOL(zcrypt_card_free); + +static void zcrypt_card_release(struct kref *kref) +{ + struct zcrypt_card *zdev = + container_of(kref, struct zcrypt_card, refcount); + zcrypt_card_free(zdev); +} + +void zcrypt_card_get(struct zcrypt_card *zc) +{ + kref_get(&zc->refcount); +} +EXPORT_SYMBOL(zcrypt_card_get); + +int zcrypt_card_put(struct zcrypt_card *zc) +{ + return kref_put(&zc->refcount, zcrypt_card_release); +} +EXPORT_SYMBOL(zcrypt_card_put); + +/** + * zcrypt_card_register() - Register a crypto card device. + * @zc: Pointer to a crypto card device + * + * Register a crypto card device. Returns 0 if successful. + */ +int zcrypt_card_register(struct zcrypt_card *zc) +{ + int rc; + + rc = sysfs_create_group(&zc->card->ap_dev.device.kobj, + &zcrypt_card_attr_group); + if (rc) + return rc; + + spin_lock(&zcrypt_list_lock); + list_add_tail(&zc->list, &zcrypt_card_list); + spin_unlock(&zcrypt_list_lock); + + zc->online = 1; + return rc; +} +EXPORT_SYMBOL(zcrypt_card_register); + +/** + * zcrypt_card_unregister(): Unregister a crypto card device. + * @zc: Pointer to crypto card device + * + * Unregister a crypto card device. + */ +void zcrypt_card_unregister(struct zcrypt_card *zc) +{ + spin_lock(&zcrypt_list_lock); + list_del_init(&zc->list); + spin_unlock(&zcrypt_list_lock); + sysfs_remove_group(&zc->card->ap_dev.device.kobj, + &zcrypt_card_attr_group); +} +EXPORT_SYMBOL(zcrypt_card_unregister); diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 4bb13eadd0f1..c7d48a18199e 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "ap_bus.h" #include "zcrypt_api.h" @@ -54,108 +55,195 @@ #define CEX2A_CLEANUP_TIME (15*HZ) #define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME -static struct ap_device_id zcrypt_cex2a_ids[] = { - { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX3A) }, - { /* end of list */ }, -}; - -MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static int zcrypt_cex2a_probe(struct ap_device *ap_dev); -static void zcrypt_cex2a_remove(struct ap_device *ap_dev); +static struct ap_device_id zcrypt_cex2a_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX2A, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3A, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { /* end of list */ }, +}; + +MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_card_ids); -static struct ap_driver zcrypt_cex2a_driver = { - .probe = zcrypt_cex2a_probe, - .remove = zcrypt_cex2a_remove, - .ids = zcrypt_cex2a_ids, - .request_timeout = CEX2A_CLEANUP_TIME, +static struct ap_device_id zcrypt_cex2a_queue_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX2A, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3A, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { /* end of list */ }, }; +MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_queue_ids); + /** - * Probe function for CEX2A cards. It always accepts the AP device - * since the bus_match already checked the hardware type. + * Probe function for CEX2A card devices. It always accepts the AP device + * since the bus_match already checked the card type. * @ap_dev: pointer to the AP device. */ -static int zcrypt_cex2a_probe(struct ap_device *ap_dev) +static int zcrypt_cex2a_card_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}; + /* + * Normalized speed ratings per crypto adapter + * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY + */ + static const int CEX2A_SPEED_IDX[] = { + 800, 1000, 2000, 900, 1200, 2400, 0, 0}; + static const int CEX3A_SPEED_IDX[] = { + 400, 500, 1000, 450, 550, 1200, 0, 0}; + + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc; int rc = 0; + zc = zcrypt_card_alloc(); + if (!zc) + return -ENOMEM; + zc->card = ac; + ac->private = zc; + + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) { + zc->min_mod_size = CEX2A_MIN_MOD_SIZE; + zc->max_mod_size = CEX2A_MAX_MOD_SIZE; + memcpy(zc->speed_rating, CEX2A_SPEED_IDX, + sizeof(CEX2A_SPEED_IDX)); + zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; + zc->type_string = "CEX2A"; + zc->user_space_type = ZCRYPT_CEX2A; + } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX3A) { + zc->min_mod_size = CEX2A_MIN_MOD_SIZE; + zc->max_mod_size = CEX2A_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; + if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) && + ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) { + zc->max_mod_size = CEX3A_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; + } + memcpy(zc->speed_rating, CEX3A_SPEED_IDX, + sizeof(CEX3A_SPEED_IDX)); + zc->type_string = "CEX3A"; + zc->user_space_type = ZCRYPT_CEX3A; + } else { + zcrypt_card_free(zc); + return -ENODEV; + } + zc->online = 1; + + rc = zcrypt_card_register(zc); + if (rc) { + ac->private = NULL; + zcrypt_card_free(zc); + } + + return rc; +} + +/** + * This is called to remove the CEX2A card driver information + * if an AP card device is removed. + */ +static void zcrypt_cex2a_card_remove(struct ap_device *ap_dev) +{ + struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; + + if (zc) + zcrypt_card_unregister(zc); +} + +static struct ap_driver zcrypt_cex2a_card_driver = { + .probe = zcrypt_cex2a_card_probe, + .remove = zcrypt_cex2a_card_remove, + .ids = zcrypt_cex2a_card_ids, +}; + +/** + * Probe function for CEX2A queue devices. It always accepts the AP device + * since the bus_match already checked the queue type. + * @ap_dev: pointer to the AP device. + */ +static int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = NULL; + int rc; + switch (ap_dev->device_type) { case AP_DEVICE_TYPE_CEX2A: - zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE); - if (!zdev) + zq = zcrypt_queue_alloc(CEX2A_MAX_RESPONSE_SIZE); + if (!zq) return -ENOMEM; - zdev->user_space_type = ZCRYPT_CEX2A; - zdev->type_string = "CEX2A"; - zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; - zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; - zdev->short_crt = 1; - 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: - zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE); - if (!zdev) + zq = zcrypt_queue_alloc(CEX3A_MAX_RESPONSE_SIZE); + if (!zq) return -ENOMEM; - zdev->user_space_type = ZCRYPT_CEX3A; - zdev->type_string = "CEX3A"; - zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; - zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; - if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && - ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { - zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; - } - zdev->short_crt = 1; - memcpy(zdev->speed_rating, CEX3A_SPEED_IDX, - sizeof(CEX3A_SPEED_IDX)); break; } - if (!zdev) + if (!zq) return -ENODEV; - 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); + zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); + zq->queue = aq; + zq->online = 1; + atomic_set(&zq->load, 0); + ap_queue_init_reply(aq, &zq->reply); + aq->request_timeout = CEX2A_CLEANUP_TIME, + aq->private = zq; + rc = zcrypt_queue_register(zq); if (rc) { - ap_dev->private = NULL; - zcrypt_device_free(zdev); + aq->private = NULL; + zcrypt_queue_free(zq); } + return rc; } /** - * This is called to remove the extended CEX2A driver information - * if an AP device is removed. + * This is called to remove the CEX2A queue driver information + * if an AP queue device is removed. */ -static void zcrypt_cex2a_remove(struct ap_device *ap_dev) +static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = ap_dev->private; + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = aq->private; - zcrypt_device_unregister(zdev); + ap_queue_remove(aq); + if (zq) + zcrypt_queue_unregister(zq); } +static struct ap_driver zcrypt_cex2a_queue_driver = { + .probe = zcrypt_cex2a_queue_probe, + .remove = zcrypt_cex2a_queue_remove, + .suspend = ap_queue_suspend, + .resume = ap_queue_resume, + .ids = zcrypt_cex2a_queue_ids, +}; + int __init zcrypt_cex2a_init(void) { - return ap_driver_register(&zcrypt_cex2a_driver, THIS_MODULE, "cex2a"); + int rc; + + rc = ap_driver_register(&zcrypt_cex2a_card_driver, + THIS_MODULE, "cex2acard"); + if (rc) + return rc; + + rc = ap_driver_register(&zcrypt_cex2a_queue_driver, + THIS_MODULE, "cex2aqueue"); + if (rc) + ap_driver_unregister(&zcrypt_cex2a_card_driver); + + return rc; } void __exit zcrypt_cex2a_exit(void) { - ap_driver_unregister(&zcrypt_cex2a_driver); + ap_driver_unregister(&zcrypt_cex2a_queue_driver); + ap_driver_unregister(&zcrypt_cex2a_card_driver); } module_init(zcrypt_cex2a_init); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index ff28ad543c30..4e91163d70a6 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "ap_bus.h" #include "zcrypt_api.h" @@ -34,160 +35,246 @@ */ #define CEX4_CLEANUP_TIME (900*HZ) -static struct ap_device_id zcrypt_cex4_ids[] = { - { AP_DEVICE(AP_DEVICE_TYPE_CEX4) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX5) }, - { /* end of list */ }, -}; - -MODULE_DEVICE_TABLE(ap, zcrypt_cex4_ids); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \ "Copyright IBM Corp. 2012"); MODULE_LICENSE("GPL"); -static int zcrypt_cex4_probe(struct ap_device *ap_dev); -static void zcrypt_cex4_remove(struct ap_device *ap_dev); +static struct ap_device_id zcrypt_cex4_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX4, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX5, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { /* end of list */ }, +}; + +MODULE_DEVICE_TABLE(ap, zcrypt_cex4_card_ids); -static struct ap_driver zcrypt_cex4_driver = { - .probe = zcrypt_cex4_probe, - .remove = zcrypt_cex4_remove, - .ids = zcrypt_cex4_ids, - .request_timeout = CEX4_CLEANUP_TIME, +static struct ap_device_id zcrypt_cex4_queue_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX4, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX5, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { /* end of list */ }, }; +MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids); + /** - * Probe function for CEX4 cards. It always accepts the AP device + * Probe function for CEX4 card device. It always accepts the AP device * since the bus_match already checked the hardware type. * @ap_dev: pointer to the AP device. */ -static int zcrypt_cex4_probe(struct ap_device *ap_dev) +static int zcrypt_cex4_card_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}; + static const int CEX4A_SPEED_IDX[] = { + 5, 6, 59, 20, 115, 581, 0, 0}; + static const int CEX5A_SPEED_IDX[] = { + 3, 3, 6, 8, 32, 218, 0, 0}; + static const int CEX4C_SPEED_IDX[] = { + 24, 25, 82, 41, 138, 1111, 79, 8}; + static const int CEX5C_SPEED_IDX[] = { + 10, 14, 23, 17, 45, 242, 63, 4}; + static const int CEX4P_SPEED_IDX[] = { + 142, 198, 1852, 203, 331, 1563, 0, 8}; + static const int CEX5P_SPEED_IDX[] = { + 49, 67, 131, 52, 85, 287, 0, 4}; + + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc; int rc = 0; - switch (ap_dev->device_type) { - case AP_DEVICE_TYPE_CEX4: - case AP_DEVICE_TYPE_CEX5: - if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) { - zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE); - if (!zdev) - return -ENOMEM; - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { - zdev->type_string = "CEX4A"; - memcpy(zdev->speed_rating, CEX4A_SPEED_IDX, - sizeof(CEX4A_SPEED_IDX)); - } else { - zdev->type_string = "CEX5A"; - 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; - if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && - ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { - zdev->max_mod_size = - CEX4A_MAX_MOD_SIZE_4K; - zdev->max_exp_bit_length = - CEX4A_MAX_MOD_SIZE_4K; - } else { - zdev->max_mod_size = - CEX4A_MAX_MOD_SIZE_2K; - zdev->max_exp_bit_length = - CEX4A_MAX_MOD_SIZE_2K; - } - zdev->short_crt = 1; - 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) - return -ENOMEM; - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { - zdev->type_string = "CEX4C"; - memcpy(zdev->speed_rating, CEX4C_SPEED_IDX, - sizeof(CEX4C_SPEED_IDX)); - } else { - zdev->type_string = "CEX5C"; - 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; - 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(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) - return -ENOMEM; - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { - zdev->type_string = "CEX4P"; - memcpy(zdev->speed_rating, CEX4P_SPEED_IDX, - sizeof(CEX4P_SPEED_IDX)); - } else { - zdev->type_string = "CEX5P"; - 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; - 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(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_EP11); + zc = zcrypt_card_alloc(); + if (!zc) + return -ENOMEM; + zc->card = ac; + ac->private = zc; + if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) { + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { + zc->type_string = "CEX4A"; + zc->user_space_type = ZCRYPT_CEX4; + memcpy(zc->speed_rating, CEX4A_SPEED_IDX, + sizeof(CEX4A_SPEED_IDX)); + } else { + zc->type_string = "CEX5A"; + zc->user_space_type = ZCRYPT_CEX5; + memcpy(zc->speed_rating, CEX5A_SPEED_IDX, + sizeof(CEX5A_SPEED_IDX)); } - break; - } - if (!zdev) + zc->min_mod_size = CEX4A_MIN_MOD_SIZE; + if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) && + ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) { + zc->max_mod_size = CEX4A_MAX_MOD_SIZE_4K; + zc->max_exp_bit_length = + CEX4A_MAX_MOD_SIZE_4K; + } else { + zc->max_mod_size = CEX4A_MAX_MOD_SIZE_2K; + zc->max_exp_bit_length = + CEX4A_MAX_MOD_SIZE_2K; + } + } else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) { + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { + zc->type_string = "CEX4C"; + /* wrong user space type, must be CEX4 + * just keep it for cca compatibility + */ + zc->user_space_type = ZCRYPT_CEX3C; + memcpy(zc->speed_rating, CEX4C_SPEED_IDX, + sizeof(CEX4C_SPEED_IDX)); + } else { + zc->type_string = "CEX5C"; + /* wrong user space type, must be CEX5 + * just keep it for cca compatibility + */ + zc->user_space_type = ZCRYPT_CEX3C; + memcpy(zc->speed_rating, CEX5C_SPEED_IDX, + sizeof(CEX5C_SPEED_IDX)); + } + zc->min_mod_size = CEX4C_MIN_MOD_SIZE; + zc->max_mod_size = CEX4C_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; + } else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) { + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { + zc->type_string = "CEX4P"; + zc->user_space_type = ZCRYPT_CEX4; + memcpy(zc->speed_rating, CEX4P_SPEED_IDX, + sizeof(CEX4P_SPEED_IDX)); + } else { + zc->type_string = "CEX5P"; + zc->user_space_type = ZCRYPT_CEX5; + memcpy(zc->speed_rating, CEX5P_SPEED_IDX, + sizeof(CEX5P_SPEED_IDX)); + } + zc->min_mod_size = CEX4C_MIN_MOD_SIZE; + zc->max_mod_size = CEX4C_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; + } else { + zcrypt_card_free(zc); 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); + } + zc->online = 1; + + rc = zcrypt_card_register(zc); if (rc) { - ap_dev->private = NULL; - zcrypt_device_free(zdev); + ac->private = NULL; + zcrypt_card_free(zc); } + return rc; } /** - * This is called to remove the extended CEX4 driver information - * if an AP device is removed. + * This is called to remove the CEX4 card driver information + * if an AP card device is removed. */ -static void zcrypt_cex4_remove(struct ap_device *ap_dev) +static void zcrypt_cex4_card_remove(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = ap_dev->private; + struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; - if (zdev) { - zcrypt_device_unregister(zdev); + if (zc) + zcrypt_card_unregister(zc); +} + +static struct ap_driver zcrypt_cex4_card_driver = { + .probe = zcrypt_cex4_card_probe, + .remove = zcrypt_cex4_card_remove, + .ids = zcrypt_cex4_card_ids, +}; + +/** + * Probe function for CEX4 queue device. It always accepts the AP device + * since the bus_match already checked the hardware type. + * @ap_dev: pointer to the AP device. + */ +static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq; + int rc; + + if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) { + zq = zcrypt_queue_alloc(CEX4A_MAX_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, + MSGTYPE50_VARIANT_DEFAULT); + } else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) { + zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); + } else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) { + zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_EP11); + } else { + return -ENODEV; } + zq->queue = aq; + zq->online = 1; + atomic_set(&zq->load, 0); + ap_queue_init_reply(aq, &zq->reply); + aq->request_timeout = CEX4_CLEANUP_TIME, + aq->private = zq; + rc = zcrypt_queue_register(zq); + if (rc) { + aq->private = NULL; + zcrypt_queue_free(zq); + } + + return rc; } +/** + * This is called to remove the CEX4 queue driver information + * if an AP queue device is removed. + */ +static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = aq->private; + + ap_queue_remove(aq); + if (zq) + zcrypt_queue_unregister(zq); +} + +static struct ap_driver zcrypt_cex4_queue_driver = { + .probe = zcrypt_cex4_queue_probe, + .remove = zcrypt_cex4_queue_remove, + .suspend = ap_queue_suspend, + .resume = ap_queue_resume, + .ids = zcrypt_cex4_queue_ids, +}; + int __init zcrypt_cex4_init(void) { - return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4"); + int rc; + + rc = ap_driver_register(&zcrypt_cex4_card_driver, + THIS_MODULE, "cex4card"); + if (rc) + return rc; + + rc = ap_driver_register(&zcrypt_cex4_queue_driver, + THIS_MODULE, "cex4queue"); + if (rc) + ap_driver_unregister(&zcrypt_cex4_card_driver); + + return rc; } void __exit zcrypt_cex4_exit(void) { - ap_driver_unregister(&zcrypt_cex4_driver); + ap_driver_unregister(&zcrypt_cex4_queue_driver); + ap_driver_unregister(&zcrypt_cex4_card_driver); } module_init(zcrypt_cex4_init); diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index de1b6c1d172c..09247331e9fb 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -87,7 +87,7 @@ struct error_hdr { #define REP88_ERROR_OPERAND 0x84 /* CEX2A */ #define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */ -static inline int convert_error(struct zcrypt_device *zdev, +static inline int convert_error(struct zcrypt_queue *zq, struct ap_message *reply) { struct error_hdr *ehdr = reply->message; @@ -110,11 +110,13 @@ static inline int convert_error(struct zcrypt_device *zdev, * and then repeat the request. */ atomic_set(&zcrypt_rescan_req, 1); - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), zq->online, ehdr->reply_code); return -EAGAIN; case REP82_ERROR_TRANSPORT_FAIL: @@ -122,19 +124,23 @@ static inline int convert_error(struct zcrypt_device *zdev, // REP88_ERROR_MODULE_FAILURE // '10' CEX2A /* If a card fails disable it and repeat the request. */ atomic_set(&zcrypt_rescan_req, 1); - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), zq->online, ehdr->reply_code); return -EAGAIN; default: - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), zq->online, ehdr->reply_code); return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index fb97479af3f8..a9873b436115 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -53,9 +53,6 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *, - struct ap_message *); - /** * The type 50 message family is associated with a CEX2A card. * @@ -208,13 +205,13 @@ unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode) /** * Convert a ICAMEX message to a type50 MEX message. * - * @zdev: crypto device pointer - * @zreq: crypto request pointer + * @zq: crypto queue pointer + * @ap_msg: crypto request pointer * @mex: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, +static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo *mex) { @@ -266,13 +263,13 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, /** * Convert a ICACRT message to a type50 CRT message. * - * @zdev: crypto device pointer - * @zreq: crypto request pointer + * @zq: crypto queue pointer + * @ap_msg: crypto request pointer * @crt: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, +static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo_crt *crt) { @@ -315,7 +312,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, u = crb2->u + sizeof(crb2->u) - short_len; inp = crb2->message + sizeof(crb2->message) - mod_len; } else if ((mod_len <= 512) && /* up to 4096 bit key size */ - (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE)) { /* >= CEX3A */ + (zq->zcard->max_mod_size == CEX3A_MAX_MOD_SIZE)) { struct type50_crb3_msg *crb3 = ap_msg->message; memset(crb3, 0, sizeof(*crb3)); ap_msg->length = sizeof(*crb3); @@ -349,14 +346,14 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, /** * Copy results from a type 80 reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @data: pointer to user output data * @length: size of user output data * * Returns 0 on success or -EFAULT. */ -static int convert_type80(struct zcrypt_device *zdev, +static int convert_type80(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -366,16 +363,18 @@ static int convert_type80(struct zcrypt_device *zdev, if (t80h->len < sizeof(*t80h) + outputdatalength) { /* The result is too short, the CEX2A card may not do that.. */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), - zdev->online, t80h->code); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online, t80h->code); return -EAGAIN; /* repeat the request on a different device. */ } - if (zdev->user_space_type == ZCRYPT_CEX2A) + if (zq->zcard->user_space_type == ZCRYPT_CEX2A) BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); else BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE); @@ -385,7 +384,7 @@ static int convert_type80(struct zcrypt_device *zdev, return 0; } -static int convert_response(struct zcrypt_device *zdev, +static int convert_response(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -394,16 +393,19 @@ static int convert_response(struct zcrypt_device *zdev, switch (((unsigned char *) reply->message)[1]) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE80_RSP_CODE: - return convert_type80(zdev, reply, + return convert_type80(zq, reply, outputdata, outputdatalength); default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -412,11 +414,11 @@ static int convert_response(struct zcrypt_device *zdev, * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". * It is called from tasklet context. - * @ap_dev: pointer to the AP device + * @aq: pointer to the AP device * @msg: pointer to the AP message * @reply: pointer to the AP reply message */ -static void zcrypt_cex2a_receive(struct ap_device *ap_dev, +static void zcrypt_cex2a_receive(struct ap_queue *aq, struct ap_message *msg, struct ap_message *reply) { @@ -432,7 +434,7 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev, goto out; /* ap_msg->rc indicates the error */ t80h = reply->message; if (t80h->type == TYPE80_RSP_CODE) { - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A) + if (aq->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) length = min_t(int, CEX2A_MAX_RESPONSE_SIZE, t80h->len); else @@ -450,11 +452,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0); /** * The request distributor calls this function if it picked the CEX2A * device to handle a modexpo request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * CEX2A device to the request distributor * @mex: pointer to the modexpo request buffer */ -static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, +static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq, struct ica_rsa_modexpo *mex) { struct ap_message ap_msg; @@ -462,7 +464,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, int rc; ap_init_message(&ap_msg); - if (zdev->user_space_type == ZCRYPT_CEX2A) + if (zq->zcard->user_space_type == ZCRYPT_CEX2A) ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); else @@ -474,20 +476,20 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; - rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex); + rc = ICAMEX_msg_to_type50MEX_msg(zq, &ap_msg, mex); if (rc) goto out_free; init_completion(&work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response(zdev, &ap_msg, mex->outputdata, + rc = convert_response(zq, &ap_msg, mex->outputdata, mex->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); out_free: kfree(ap_msg.message); return rc; @@ -496,11 +498,11 @@ out_free: /** * The request distributor calls this function if it picked the CEX2A * device to handle a modexpo_crt request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * CEX2A device to the request distributor * @crt: pointer to the modexpoc_crt request buffer */ -static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, +static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq, struct ica_rsa_modexpo_crt *crt) { struct ap_message ap_msg; @@ -508,7 +510,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, int rc; ap_init_message(&ap_msg); - if (zdev->user_space_type == ZCRYPT_CEX2A) + if (zq->zcard->user_space_type == ZCRYPT_CEX2A) ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); else @@ -520,20 +522,20 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; - rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt); + rc = ICACRT_msg_to_type50CRT_msg(zq, &ap_msg, crt); if (rc) goto out_free; init_completion(&work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response(zdev, &ap_msg, crt->outputdata, + rc = convert_response(zq, &ap_msg, crt->outputdata, crt->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); out_free: kfree(ap_msg.message); return rc; diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 957a88d5768b..c6cfb9acec19 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -60,9 +60,6 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *, - struct ap_message *); - /** * CPRB * Note that all shorts, ints and longs are little-endian. @@ -258,13 +255,13 @@ int speed_idx_ep11(int req_type) /** * Convert a ICAMEX message to a type6 MEX message. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @ap_msg: pointer to AP message * @mex: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, +static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo *mex) { @@ -279,11 +276,6 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, .ulen = 10, .only_rule = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '} }; - static struct function_and_rules_block static_pke_fnr_MCL2 = { - .function_code = {'P', 'K'}, - .ulen = 10, - .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} - }; struct { struct type6_hdr hdr; struct CPRBX cprbx; @@ -310,11 +302,10 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); msg->cprbx = static_cprbx; - msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1; - msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? - static_pke_fnr_MCL2 : static_pke_fnr; + msg->fr = static_pke_fnr; msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx); @@ -325,13 +316,13 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, /** * Convert a ICACRT message to a type6 CRT message. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @ap_msg: pointer to AP message * @crt: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, +static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo_crt *crt) { @@ -347,11 +338,6 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} }; - static struct function_and_rules_block static_pkd_fnr_MCL2 = { - .function_code = {'P', 'D'}, - .ulen = 10, - .only_rule = {'P', 'K', 'C', 'S', '-', '1', '.', '2'} - }; struct { struct type6_hdr hdr; struct CPRBX cprbx; @@ -378,12 +364,11 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); msg->cprbx = static_cprbx; - msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); msg->cprbx.req_parml = msg->cprbx.rpl_msgbl = size - sizeof(msg->hdr) - sizeof(msg->cprbx); - msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? - static_pkd_fnr_MCL2 : static_pkd_fnr; + msg->fr = static_pkd_fnr; ap_msg->length = size; return 0; @@ -392,7 +377,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, /** * Convert a XCRB message to a type6 CPRB message. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @ap_msg: pointer to AP message * @xcRB: pointer to user input data * @@ -405,7 +390,8 @@ struct type86_fmt2_msg { static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, struct ica_xcRB *xcRB, - unsigned int *fcode) + unsigned int *fcode, + unsigned short **dom) { static struct type6_hdr static_type6_hdrX = { .type = 0x06, @@ -486,6 +472,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, sizeof(msg->hdr.function_code)); *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1]; + *dom = (unsigned short *)&msg->cprbx.domain; if (memcmp(function_code, "US", 2) == 0) ap_msg->special = 1; @@ -497,6 +484,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, copy_from_user(req_data, xcRB->request_data_address, xcRB->request_data_length)) return -EFAULT; + return 0; } @@ -504,6 +492,7 @@ 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}, @@ -556,14 +545,30 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg, return -EFAULT; } - *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF); + if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ + switch (msg->pld_lenfmt & 0x03) { + case 1: + lfmt = 2; + break; + case 2: + lfmt = 3; + break; + default: + return -EINVAL; + } + } else { + lfmt = 1; /* length format #1 */ + } + payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); + *fcode = payload_hdr->func_val & 0xFFFF; + return 0; } /** * Copy results from a type 86 ICA reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @data: pointer to user output data * @length: size of user output data @@ -585,7 +590,7 @@ struct type86_ep11_reply { struct ep11_cprb cprbx; } __packed; -static int convert_type86_ica(struct zcrypt_device *zdev, +static int convert_type86_ica(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -640,18 +645,22 @@ static int convert_type86_ica(struct zcrypt_device *zdev, if (service_rc == 8 && service_rs == 770) return -EINVAL; if (service_rc == 8 && service_rs == 783) { - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; + zq->zcard->min_mod_size = + PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } if (service_rc == 12 && service_rs == 769) return -EINVAL; if (service_rc == 8 && service_rs == 72) return -EINVAL; - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online, msg->hdr.reply_code); return -EAGAIN; /* repeat the request on a different device. */ } @@ -688,13 +697,13 @@ static int convert_type86_ica(struct zcrypt_device *zdev, /** * Copy results from a type 86 XCRB reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @xcRB: pointer to XCRB * * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. */ -static int convert_type86_xcrb(struct zcrypt_device *zdev, +static int convert_type86_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ica_xcRB *xcRB) { @@ -719,13 +728,13 @@ static int convert_type86_xcrb(struct zcrypt_device *zdev, /** * Copy results from a type 86 EP11 XCRB reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @xcRB: pointer to EP11 user request block * * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. */ -static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev, +static int convert_type86_ep11_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ep11_urb *xcRB) { @@ -743,7 +752,7 @@ static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev, return 0; } -static int convert_type86_rng(struct zcrypt_device *zdev, +static int convert_type86_rng(struct zcrypt_queue *zq, struct ap_message *reply, char *buffer) { @@ -760,7 +769,7 @@ static int convert_type86_rng(struct zcrypt_device *zdev, return msg->fmt2.count2; } -static int convert_response_ica(struct zcrypt_device *zdev, +static int convert_response_ica(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -771,35 +780,38 @@ static int convert_response_ica(struct zcrypt_device *zdev, switch (((unsigned char *) reply->message)[1]) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE86_RSP_CODE: if (msg->cprbx.ccp_rtcode && (msg->cprbx.ccp_rscode == 0x14f) && (outputdatalength > 256)) { - if (zdev->max_exp_bit_length <= 17) { - zdev->max_exp_bit_length = 17; + if (zq->zcard->max_exp_bit_length <= 17) { + zq->zcard->max_exp_bit_length = 17; return -EAGAIN; } else return -EINVAL; } if (msg->hdr.reply_code) - return convert_error(zdev, reply); + return convert_error(zq, reply); if (msg->cprbx.cprb_ver_id == 0x02) - return convert_type86_ica(zdev, reply, + return convert_type86_ica(zq, reply, outputdata, outputdatalength); /* Fall through, no break, incorrect cprb version is an unknown * response */ default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } -static int convert_response_xcrb(struct zcrypt_device *zdev, +static int convert_response_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ica_xcRB *xcRB) { @@ -810,28 +822,31 @@ static int convert_response_xcrb(struct zcrypt_device *zdev, case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE86_RSP_CODE: if (msg->hdr.reply_code) { memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32)); - return convert_error(zdev, reply); + return convert_error(zq, reply); } if (msg->cprbx.cprb_ver_id == 0x02) - return convert_type86_xcrb(zdev, reply, xcRB); + return convert_type86_xcrb(zq, reply, xcRB); /* Fall through, no break, incorrect cprb version is an unknown * response */ default: /* Unknown response type, this should NEVER EVER happen */ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } -static int convert_response_ep11_xcrb(struct zcrypt_device *zdev, +static int convert_response_ep11_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ep11_urb *xcRB) { struct type86_ep11_reply *msg = reply->message; @@ -840,24 +855,27 @@ static int convert_response_ep11_xcrb(struct zcrypt_device *zdev, switch (((unsigned char *)reply->message)[1]) { case TYPE82_RSP_CODE: case TYPE87_RSP_CODE: - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE86_RSP_CODE: if (msg->hdr.reply_code) - return convert_error(zdev, reply); + return convert_error(zq, reply); if (msg->cprbx.cprb_ver_id == 0x04) - return convert_type86_ep11_xcrb(zdev, reply, xcRB); + return convert_type86_ep11_xcrb(zq, reply, xcRB); /* Fall through, no break, incorrect cprb version is an unknown resp.*/ default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } -static int convert_response_rng(struct zcrypt_device *zdev, +static int convert_response_rng(struct zcrypt_queue *zq, struct ap_message *reply, char *data) { @@ -871,15 +889,18 @@ static int convert_response_rng(struct zcrypt_device *zdev, if (msg->hdr.reply_code) return -EINVAL; if (msg->cprbx.cprb_ver_id == 0x02) - return convert_type86_rng(zdev, reply, data); + return convert_type86_rng(zq, reply, data); /* Fall through, no break, incorrect cprb version is an unknown * response */ default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -888,11 +909,11 @@ static int convert_response_rng(struct zcrypt_device *zdev, * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". * It is called from tasklet context. - * @ap_dev: pointer to the AP device + * @aq: pointer to the AP queue * @msg: pointer to the AP message * @reply: pointer to the AP reply message */ -static void zcrypt_msgtype6_receive(struct ap_device *ap_dev, +static void zcrypt_msgtype6_receive(struct ap_queue *aq, struct ap_message *msg, struct ap_message *reply) { @@ -937,11 +958,11 @@ out: * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". * It is called from tasklet context. - * @ap_dev: pointer to the AP device + * @aq: pointer to the AP queue * @msg: pointer to the AP message * @reply: pointer to the AP reply message */ -static void zcrypt_msgtype6_receive_ep11(struct ap_device *ap_dev, +static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, struct ap_message *msg, struct ap_message *reply) { @@ -981,11 +1002,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0); /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a modexpo request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @mex: pointer to the modexpo request buffer */ -static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, struct ica_rsa_modexpo *mex) { struct ap_message ap_msg; @@ -1002,21 +1023,21 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; - rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); + rc = ICAMEX_msg_to_type6MEX_msgX(zq, &ap_msg, mex); if (rc) goto out_free; init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&resp_type.work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response_ica(zdev, &ap_msg, + rc = convert_response_ica(zq, &ap_msg, mex->outputdata, mex->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); out_free: free_page((unsigned long) ap_msg.message); return rc; @@ -1025,11 +1046,11 @@ out_free: /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a modexpo_crt request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @crt: pointer to the modexpoc_crt request buffer */ -static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, struct ica_rsa_modexpo_crt *crt) { struct ap_message ap_msg; @@ -1046,21 +1067,22 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; - rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); + rc = ICACRT_msg_to_type6CRT_msgX(zq, &ap_msg, crt); if (rc) goto out_free; init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&resp_type.work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response_ica(zdev, &ap_msg, + rc = convert_response_ica(zq, &ap_msg, crt->outputdata, crt->outputdatalength); - } else + } else { /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); + } out_free: free_page((unsigned long) ap_msg.message); return rc; @@ -1068,7 +1090,7 @@ out_free: unsigned int get_cprb_fc(struct ica_xcRB *xcRB, struct ap_message *ap_msg, - int *func_code) + unsigned int *func_code, unsigned short **dom) { struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_XCRB, @@ -1088,7 +1110,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, return -ENOMEM; } memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); - rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code); + rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom); if (rc) { kzfree(ap_msg->message); kzfree(ap_msg->private); @@ -1099,11 +1121,11 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a send_cprb request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @xcRB: pointer to the send_cprb request buffer */ -static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq, struct ica_xcRB *xcRB, struct ap_message *ap_msg) { @@ -1111,15 +1133,15 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, struct response_type *rtype = (struct response_type *)(ap_msg->private); init_completion(&rtype->work); - ap_queue_message(zdev->ap_dev, ap_msg); + ap_queue_message(zq->queue, ap_msg); rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { rc = ap_msg->rc; if (rc == 0) - rc = convert_response_xcrb(zdev, ap_msg, xcRB); + rc = convert_response_xcrb(zq, ap_msg, xcRB); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, ap_msg); + ap_cancel_message(zq->queue, ap_msg); kzfree(ap_msg->message); kzfree(ap_msg->private); @@ -1128,7 +1150,7 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, struct ap_message *ap_msg, - int *func_code) + unsigned int *func_code) { struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_EP11, @@ -1159,11 +1181,11 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, /** * The request distributor calls this function if it picked the CEX4P * device to handle a send_ep11_cprb request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * CEX4P device to the request distributor * @xcRB: pointer to the ep11 user request block */ -static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_queue *zq, struct ep11_urb *xcrb, struct ap_message *ap_msg) { @@ -1196,7 +1218,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, */ if (!((msg->cprbx.flags & 0x80) == 0x80)) { msg->cprbx.target_id = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); + AP_QID_QUEUE(zq->queue->qid); if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ switch (msg->pld_lenfmt & 0x03) { @@ -1214,26 +1236,27 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, } payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); payload_hdr->dom_val = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); + AP_QID_QUEUE(zq->queue->qid); } init_completion(&rtype->work); - ap_queue_message(zdev->ap_dev, ap_msg); + ap_queue_message(zq->queue, ap_msg); rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { rc = ap_msg->rc; if (rc == 0) - rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb); + rc = convert_response_ep11_xcrb(zq, ap_msg, xcrb); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, ap_msg); + ap_cancel_message(zq->queue, ap_msg); kzfree(ap_msg->message); kzfree(ap_msg->private); return rc; } -unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) +unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, + unsigned int *domain) { struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_XCRB, @@ -1253,7 +1276,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) } memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); - rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE); + rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain); *func_code = HWRNG; return 0; @@ -1262,11 +1285,11 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to generate random data. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @buffer: pointer to a memory page to return random data */ -static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, char *buffer, struct ap_message *ap_msg) { struct { @@ -1281,18 +1304,18 @@ static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, struct response_type *rtype = (struct response_type *)(ap_msg->private); int rc; - msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); init_completion(&rtype->work); - ap_queue_message(zdev->ap_dev, ap_msg); + ap_queue_message(zq->queue, ap_msg); rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { rc = ap_msg->rc; if (rc == 0) - rc = convert_response_rng(zdev, ap_msg, buffer); + rc = convert_response_rng(zq, ap_msg, buffer); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, ap_msg); + ap_cancel_message(zq->queue, ap_msg); kzfree(ap_msg->message); kzfree(ap_msg->private); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index a360dbe3c7d2..7a0d5b57821f 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -116,9 +116,11 @@ struct type86_fmt2_ext { unsigned int offset4; /* 0x00000000 */ } __packed; -unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, int *); -unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, int *); -unsigned int get_rng_fc(struct ap_message *, int *); +unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, + unsigned int *, unsigned short **); +unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, + unsigned int *); +unsigned int get_rng_fc(struct ap_message *, int *, unsigned int *); #define LOW 10 #define MEDIUM 100 @@ -134,7 +136,8 @@ int speed_idx_ep11(int); * @ap_msg: pointer to AP message */ static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg, - unsigned int random_number_length) + unsigned int random_number_length, + unsigned int *domain) { struct { struct type6_hdr hdr; @@ -172,6 +175,7 @@ static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg, msg->verb_length = 0x02; msg->key_length = 0x02; ap_msg->length = sizeof(*msg); + *domain = (unsigned short)msg->cprbx.domain; } void zcrypt_msgtype6_init(void); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 43de39c74944..26ceaa696765 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "ap_bus.h" #include "zcrypt_api.h" @@ -62,142 +63,34 @@ struct response_type { #define PCIXCC_RESPONSE_TYPE_ICA 0 #define PCIXCC_RESPONSE_TYPE_XCRB 1 -static struct ap_device_id zcrypt_pcixcc_ids[] = { - { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX3C) }, - { /* end of list */ }, -}; - -MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static int zcrypt_pcixcc_probe(struct ap_device *ap_dev); -static void zcrypt_pcixcc_remove(struct ap_device *ap_dev); - -static struct ap_driver zcrypt_pcixcc_driver = { - .probe = zcrypt_pcixcc_probe, - .remove = zcrypt_pcixcc_remove, - .ids = zcrypt_pcixcc_ids, - .request_timeout = PCIXCC_CLEANUP_TIME, +static struct ap_device_id zcrypt_pcixcc_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_PCIXCC, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX2C, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3C, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { /* end of list */ }, }; -/** - * Micro-code detection function. Its sends a message to a pcixcc card - * to find out the microcode level. - * @ap_dev: pointer to the AP device. - */ -static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev) -{ - static unsigned char msg[] = { - 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00, - 0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8, - 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A, - 0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20, - 0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05, - 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, - 0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55, - 0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD, - 0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA, - 0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22, - 0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB, - 0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54, - 0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00, - 0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00, - 0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40, - 0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C, - 0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF, - 0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9, - 0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63, - 0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5, - 0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A, - 0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01, - 0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28, - 0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91, - 0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5, - 0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C, - 0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98, - 0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96, - 0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19, - 0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47, - 0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36, - 0xF1,0x3D,0x93,0x53 - }; - unsigned long long psmid; - struct CPRBX *cprbx; - char *reply; - int rc, i; - - reply = (void *) get_zeroed_page(GFP_KERNEL); - if (!reply) - return -ENOMEM; +MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids); - rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg)); - if (rc) - goto out_free; - - /* Wait for the test message to complete. */ - for (i = 0; i < 6; i++) { - msleep(300); - rc = ap_recv(ap_dev->qid, &psmid, reply, 4096); - if (rc == 0 && psmid == 0x0102030405060708ULL) - break; - } - - if (i >= 6) { - /* Got no answer. */ - rc = -ENODEV; - goto out_free; - } +static struct ap_device_id zcrypt_pcixcc_queue_ids[] = { + { .dev_type = AP_DEVICE_TYPE_PCIXCC, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX2C, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3C, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { /* end of list */ }, +}; - cprbx = (struct CPRBX *) (reply + 48); - if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33) - rc = ZCRYPT_PCIXCC_MCL2; - else - rc = ZCRYPT_PCIXCC_MCL3; -out_free: - free_page((unsigned long) reply); - return rc; -} +MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids); /** * Large random number detection function. Its sends a message to a pcixcc @@ -206,10 +99,11 @@ out_free: * * Returns 1 if large random numbers are supported, 0 if not and < 0 on error. */ -static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) +static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq) { struct ap_message ap_msg; unsigned long long psmid; + unsigned int domain; struct { struct type86_hdr hdr; struct type86_fmt2_ext fmt2; @@ -231,12 +125,12 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) if (!ap_msg.message) return -ENOMEM; - rng_type6CPRB_msgX(&ap_msg, 4); + rng_type6CPRB_msgX(&ap_msg, 4, &domain); msg = ap_msg.message; - msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(aq->qid); - rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message, + rc = ap_send(aq->qid, 0x0102030405060708ULL, ap_msg.message, ap_msg.length); if (rc) goto out_free; @@ -244,7 +138,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) /* Wait for the test message to complete. */ for (i = 0; i < 2 * HZ; i++) { msleep(1000 / HZ); - rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096); + rc = ap_recv(aq->qid, &psmid, ap_msg.message, 4096); if (rc == 0 && psmid == 0x0102030405060708ULL) break; } @@ -266,120 +160,168 @@ out_free: } /** - * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device - * since the bus_match already checked the hardware type. The PCIXCC - * cards come in two flavours: micro code level 2 and micro code level 3. - * This is checked by sending a test message to the device. - * @ap_dev: pointer to the AP device. + * Probe function for PCIXCC/CEX2C card devices. It always accepts the + * AP device since the bus_match already checked the hardware type. The + * PCIXCC cards come in two flavours: micro code level 2 and micro code + * level 3. This is checked by sending a test message to the device. + * @ap_dev: pointer to the AP card device. */ -static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) +static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev) { - struct zcrypt_device *zdev; /* * Normalized speed ratings per crypto adapter * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY */ - int PCIXCC_MCL2_SPEED_IDX[] = {10, 10, 10, 10, 10, 10, 10, 10}; - int PCIXCC_MCL3_SPEED_IDX[] = { 8, 8, 8, 8, 8, 8, 8, 8}; - int CEX2C_SPEED_IDX[] = {1000, 1400, 2400, 1100, 1500, 2600, 100, 12}; - int CEX3C_SPEED_IDX[] = { 500, 700, 1400, 550, 800, 1500, 80, 10}; + static const int CEX2C_SPEED_IDX[] = { + 1000, 1400, 2400, 1100, 1500, 2600, 100, 12}; + static const int CEX3C_SPEED_IDX[] = { + 500, 700, 1400, 550, 800, 1500, 80, 10}; + + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc; int rc = 0; - zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); - if (!zdev) + zc = zcrypt_card_alloc(); + if (!zc) return -ENOMEM; - zdev->ap_dev = ap_dev; - zdev->online = 1; - switch (ap_dev->device_type) { - case AP_DEVICE_TYPE_PCIXCC: - rc = zcrypt_pcixcc_mcl(ap_dev); - if (rc < 0) { - zcrypt_device_free(zdev); - return rc; - } - zdev->user_space_type = rc; - if (rc == ZCRYPT_PCIXCC_MCL2) { - zdev->type_string = "PCIXCC_MCL2"; - memcpy(zdev->speed_rating, PCIXCC_MCL2_SPEED_IDX, - sizeof(PCIXCC_MCL2_SPEED_IDX)); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; - zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; - zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; - } else { - zdev->type_string = "PCIXCC_MCL3"; - memcpy(zdev->speed_rating, PCIXCC_MCL3_SPEED_IDX, - sizeof(PCIXCC_MCL3_SPEED_IDX)); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; - zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; - zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; - } - break; + zc->card = ac; + ac->private = zc; + switch (ac->ap_dev.device_type) { case AP_DEVICE_TYPE_CEX2C: - zdev->user_space_type = ZCRYPT_CEX2C; - zdev->type_string = "CEX2C"; - memcpy(zdev->speed_rating, CEX2C_SPEED_IDX, + zc->user_space_type = ZCRYPT_CEX2C; + zc->type_string = "CEX2C"; + memcpy(zc->speed_rating, CEX2C_SPEED_IDX, sizeof(CEX2C_SPEED_IDX)); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; - zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; - zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; + zc->min_mod_size = PCIXCC_MIN_MOD_SIZE; + zc->max_mod_size = PCIXCC_MAX_MOD_SIZE; + zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3C: - zdev->user_space_type = ZCRYPT_CEX3C; - zdev->type_string = "CEX3C"; - memcpy(zdev->speed_rating, CEX3C_SPEED_IDX, + zc->user_space_type = ZCRYPT_CEX3C; + zc->type_string = "CEX3C"; + memcpy(zc->speed_rating, CEX3C_SPEED_IDX, sizeof(CEX3C_SPEED_IDX)); - zdev->min_mod_size = CEX3C_MIN_MOD_SIZE; - zdev->max_mod_size = CEX3C_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; + zc->min_mod_size = CEX3C_MIN_MOD_SIZE; + zc->max_mod_size = CEX3C_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; break; default: - goto out_free; + zcrypt_card_free(zc); + return -ENODEV; } - zdev->load = zdev->speed_rating[0]; + zc->online = 1; - rc = zcrypt_pcixcc_rng_supported(ap_dev); + rc = zcrypt_card_register(zc); + if (rc) { + ac->private = NULL; + zcrypt_card_free(zc); + } + + return rc; +} + +/** + * This is called to remove the PCIXCC/CEX2C card driver information + * if an AP card device is removed. + */ +static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev) +{ + struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; + + if (zc) + zcrypt_card_unregister(zc); +} + +static struct ap_driver zcrypt_pcixcc_card_driver = { + .probe = zcrypt_pcixcc_card_probe, + .remove = zcrypt_pcixcc_card_remove, + .ids = zcrypt_pcixcc_card_ids, +}; + +/** + * Probe function for PCIXCC/CEX2C queue devices. It always accepts the + * AP device since the bus_match already checked the hardware type. The + * PCIXCC cards come in two flavours: micro code level 2 and micro code + * level 3. This is checked by sending a test message to the device. + * @ap_dev: pointer to the AP card device. + */ +static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq; + int rc; + + zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->queue = aq; + zq->online = 1; + atomic_set(&zq->load, 0); + rc = zcrypt_pcixcc_rng_supported(aq); if (rc < 0) { - zcrypt_device_free(zdev); + zcrypt_queue_free(zq); return rc; } if (rc) - zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_DEFAULT); + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); else - 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); - if (rc) - goto out_free; - return 0; - - out_free: - ap_dev->private = NULL; - zcrypt_device_free(zdev); + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_NORNG); + ap_queue_init_reply(aq, &zq->reply); + aq->request_timeout = PCIXCC_CLEANUP_TIME, + aq->private = zq; + rc = zcrypt_queue_register(zq); + if (rc) { + aq->private = NULL; + zcrypt_queue_free(zq); + } return rc; } /** - * This is called to remove the extended PCIXCC/CEX2C driver information - * if an AP device is removed. + * This is called to remove the PCIXCC/CEX2C queue driver information + * if an AP queue device is removed. */ -static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) +static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = ap_dev->private; + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = aq->private; - zcrypt_device_unregister(zdev); + ap_queue_remove(aq); + if (zq) + zcrypt_queue_unregister(zq); } +static struct ap_driver zcrypt_pcixcc_queue_driver = { + .probe = zcrypt_pcixcc_queue_probe, + .remove = zcrypt_pcixcc_queue_remove, + .suspend = ap_queue_suspend, + .resume = ap_queue_resume, + .ids = zcrypt_pcixcc_queue_ids, +}; + int __init zcrypt_pcixcc_init(void) { - return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc"); + int rc; + + rc = ap_driver_register(&zcrypt_pcixcc_card_driver, + THIS_MODULE, "pcixcccard"); + if (rc) + return rc; + + rc = ap_driver_register(&zcrypt_pcixcc_queue_driver, + THIS_MODULE, "pcixccqueue"); + if (rc) + ap_driver_unregister(&zcrypt_pcixcc_card_driver); + + return rc; } void zcrypt_pcixcc_exit(void) { - ap_driver_unregister(&zcrypt_pcixcc_driver); + ap_driver_unregister(&zcrypt_pcixcc_queue_driver); + ap_driver_unregister(&zcrypt_pcixcc_card_driver); } module_init(zcrypt_pcixcc_init); diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c new file mode 100644 index 000000000000..c70b2528d9a3 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -0,0 +1,221 @@ +/* + * zcrypt 2.1.0 + * + * Copyright IBM Corp. 2001, 2012 + * Author(s): Robert Burroughs + * Eric Rossman (edrossma@us.ibm.com) + * Cornelia Huck + * + * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) + * Major cleanup & driver split: Martin Schwidefsky + * Ralph Wuerthner + * MSGTYPE restruct: Holger Dengler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zcrypt_debug.h" +#include "zcrypt_api.h" + +#include "zcrypt_msgtype6.h" +#include "zcrypt_msgtype50.h" + +/* + * Device attributes common for all crypto queue devices. + */ + +static ssize_t zcrypt_queue_online_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zcrypt_queue *zq = to_ap_queue(dev)->private; + + return snprintf(buf, PAGE_SIZE, "%d\n", zq->online); +} + +static ssize_t zcrypt_queue_online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zcrypt_queue *zq = to_ap_queue(dev)->private; + struct zcrypt_card *zc = zq->zcard; + int online; + + if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) + return -EINVAL; + + if (online && !zc->online) + return -EINVAL; + zq->online = online; + ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dman", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), online); + if (!online) + ap_flush_queue(zq->queue); + return count; +} + +static DEVICE_ATTR(online, 0644, zcrypt_queue_online_show, + zcrypt_queue_online_store); + +static struct attribute *zcrypt_queue_attrs[] = { + &dev_attr_online.attr, + NULL, +}; + +static struct attribute_group zcrypt_queue_attr_group = { + .attrs = zcrypt_queue_attrs, +}; + +void zcrypt_queue_force_online(struct zcrypt_queue *zq, int online) +{ + zq->online = online; + if (!online) + ap_flush_queue(zq->queue); +} + +struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size) +{ + struct zcrypt_queue *zq; + + zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL); + if (!zq) + return NULL; + zq->reply.message = kmalloc(max_response_size, GFP_KERNEL); + if (!zq->reply.message) + goto out_free; + zq->reply.length = max_response_size; + INIT_LIST_HEAD(&zq->list); + zq->dbf_area = zcrypt_dbf_devices; + kref_init(&zq->refcount); + return zq; + +out_free: + kfree(zq); + return NULL; +} +EXPORT_SYMBOL(zcrypt_queue_alloc); + +void zcrypt_queue_free(struct zcrypt_queue *zq) +{ + kfree(zq->reply.message); + kfree(zq); +} +EXPORT_SYMBOL(zcrypt_queue_free); + +static void zcrypt_queue_release(struct kref *kref) +{ + struct zcrypt_queue *zq = + container_of(kref, struct zcrypt_queue, refcount); + zcrypt_queue_free(zq); +} + +void zcrypt_queue_get(struct zcrypt_queue *zq) +{ + kref_get(&zq->refcount); +} +EXPORT_SYMBOL(zcrypt_queue_get); + +int zcrypt_queue_put(struct zcrypt_queue *zq) +{ + return kref_put(&zq->refcount, zcrypt_queue_release); +} +EXPORT_SYMBOL(zcrypt_queue_put); + +/** + * zcrypt_queue_register() - Register a crypto queue device. + * @zq: Pointer to a crypto queue device + * + * Register a crypto queue device. Returns 0 if successful. + */ +int zcrypt_queue_register(struct zcrypt_queue *zq) +{ + struct zcrypt_card *zc; + int rc; + + spin_lock(&zcrypt_list_lock); + zc = zq->queue->card->private; + zcrypt_card_get(zc); + zq->zcard = zc; + zq->online = 1; /* New devices are online by default. */ + ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dreg", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); + list_add_tail(&zq->list, &zc->zqueues); + zcrypt_device_count++; + spin_unlock(&zcrypt_list_lock); + + rc = sysfs_create_group(&zq->queue->ap_dev.device.kobj, + &zcrypt_queue_attr_group); + if (rc) + goto out; + get_device(&zq->queue->ap_dev.device); + + if (zq->ops->rng) { + rc = zcrypt_rng_device_add(); + if (rc) + goto out_unregister; + } + return 0; + +out_unregister: + sysfs_remove_group(&zq->queue->ap_dev.device.kobj, + &zcrypt_queue_attr_group); + put_device(&zq->queue->ap_dev.device); +out: + spin_lock(&zcrypt_list_lock); + list_del_init(&zq->list); + spin_unlock(&zcrypt_list_lock); + zcrypt_card_put(zc); + return rc; +} +EXPORT_SYMBOL(zcrypt_queue_register); + +/** + * zcrypt_queue_unregister(): Unregister a crypto queue device. + * @zq: Pointer to crypto queue device + * + * Unregister a crypto queue device. + */ +void zcrypt_queue_unregister(struct zcrypt_queue *zq) +{ + struct zcrypt_card *zc; + + zc = zq->zcard; + spin_lock(&zcrypt_list_lock); + list_del_init(&zq->list); + zcrypt_device_count--; + spin_unlock(&zcrypt_list_lock); + zcrypt_card_put(zc); + if (zq->ops->rng) + zcrypt_rng_device_remove(); + sysfs_remove_group(&zq->queue->ap_dev.device.kobj, + &zcrypt_queue_attr_group); + put_device(&zq->queue->ap_dev.device); + zcrypt_queue_put(zq); +} +EXPORT_SYMBOL(zcrypt_queue_unregister); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index ed84c07f6a51..8a57f0b1242d 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -175,7 +175,8 @@ struct ap_device_id { kernel_ulong_t driver_info; }; -#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01 +#define AP_DEVICE_ID_MATCH_CARD_TYPE 0x01 +#define AP_DEVICE_ID_MATCH_QUEUE_TYPE 0x02 /* s390 css bus devices (subchannels) */ struct css_device_id { -- cgit v1.2.3 From b886a9d1560d6c7d5d58344b16f53ab2cba5b666 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:19:58 +0200 Subject: s390/zcrypt: Introduce new zcrypt device status API Introduce new ioctl (ZDEVICESTATUS) to provide detailed information, like hardware type, domains, status and functionality of available crypto devices. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- arch/s390/include/uapi/asm/zcrypt.h | 37 ++++++++++++++++++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/uapi/asm/zcrypt.h b/arch/s390/include/uapi/asm/zcrypt.h index f2b18eacaca8..a777f87ef889 100644 --- a/arch/s390/include/uapi/asm/zcrypt.h +++ b/arch/s390/include/uapi/asm/zcrypt.h @@ -215,6 +215,42 @@ struct ep11_urb { uint64_t resp; } __attribute__((packed)); +/** + * struct zcrypt_device_status + * @hwtype: raw hardware type + * @qid: 6 bit device index, 8 bit domain + * @functions: AP device function bit field 'abcdef' + * a, b, c = reserved + * d = CCA coprocessor + * e = Accelerator + * f = EP11 coprocessor + * @online online status + * @reserved reserved + */ +struct zcrypt_device_status { + unsigned int hwtype:8; + unsigned int qid:14; + unsigned int online:1; + unsigned int functions:6; + unsigned int reserved:3; +}; + +#define MAX_ZDEV_CARDIDS 64 +#define MAX_ZDEV_DOMAINS 256 + +/** + * Maximum number of zcrypt devices + */ +#define MAX_ZDEV_ENTRIES (MAX_ZDEV_CARDIDS * MAX_ZDEV_DOMAINS) + +/** + * zcrypt_device_matrix + * Device matrix of all zcrypt devices + */ +struct zcrypt_device_matrix { + struct zcrypt_device_status device[MAX_ZDEV_ENTRIES]; +}; + #define AUTOSELECT ((unsigned int)0xFFFFFFFF) #define ZCRYPT_IOCTL_MAGIC 'z' @@ -321,6 +357,7 @@ struct ep11_urb { #define ICARSACRT _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x06, 0) #define ZSECSENDCPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x81, 0) #define ZSENDEP11CPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x04, 0) +#define ZDEVICESTATUS _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x4f, 0) /* New status calls */ #define Z90STAT_TOTALCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x40, int) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index fd0ae8cd2bee..403af9d1ebde 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -539,6 +539,29 @@ static long zcrypt_rng(char *buffer) return rc; } +static void zcrypt_device_status_mask(struct zcrypt_device_matrix *matrix) +{ + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + struct zcrypt_device_status *stat; + + memset(matrix, 0, sizeof(*matrix)); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + stat = matrix->device; + stat += AP_QID_CARD(zq->queue->qid) * MAX_ZDEV_DOMAINS; + stat += AP_QID_QUEUE(zq->queue->qid); + stat->hwtype = zc->card->ap_dev.device_type; + stat->functions = zc->card->functions >> 26; + stat->qid = zq->queue->qid; + stat->online = zq->online ? 0x01 : 0x00; + } + } + spin_unlock(&zcrypt_list_lock); +} +EXPORT_SYMBOL(zcrypt_device_status_mask); + static void zcrypt_status_mask(char status[AP_DEVICES]) { struct zcrypt_card *zc; @@ -764,6 +787,25 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; return rc; } + case ZDEVICESTATUS: { + struct zcrypt_device_matrix *device_status; + + device_status = kzalloc(sizeof(struct zcrypt_device_matrix), + GFP_KERNEL); + if (!device_status) + return -ENOMEM; + + zcrypt_device_status_mask(device_status); + + if (copy_to_user((char __user *) arg, device_status, + sizeof(struct zcrypt_device_matrix))) { + kfree(device_status); + return -EFAULT; + } + + kfree(device_status); + return 0; + } case Z90STAT_STATUS_MASK: { char status[AP_DEVICES]; zcrypt_status_mask(status); -- cgit v1.2.3 From e47de21dd35bad6d1e71482a66699cd04e83ea40 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Fri, 14 Oct 2016 14:34:51 +0200 Subject: s390/zcrypt: Fixed attrition of AP adapters and domains Currently the first eligible AP adapter respectively domain will be selected to service requests. In case of sequential workload, the very same adapter/domain will be used. The adapter/domain selection algorithm now considers the completed transactions per adaper/domain and therefore ensures a homogeneous utilization. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.h | 3 +- drivers/s390/crypto/ap_card.c | 4 +-- drivers/s390/crypto/ap_queue.c | 1 + drivers/s390/crypto/zcrypt_api.c | 63 +++++++++++++++++++++++++++------------- 4 files changed, 47 insertions(+), 24 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 54b17e142792..4dc7c88fb054 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -195,6 +195,7 @@ struct ap_card { unsigned int functions; /* AP device function bitfield. */ int queue_depth; /* AP queue depth.*/ int id; /* AP card number. */ + atomic_t total_request_count; /* # requests ever for this AP device.*/ }; #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) @@ -211,7 +212,7 @@ struct ap_queue { enum ap_state state; /* State of the AP device. */ int pendingq_count; /* # requests on pendingq list. */ int requestq_count; /* # requests on requestq list. */ - int total_request_count; /* # requests ever for this AP device. */ + int total_request_count; /* # requests ever for this AP device.*/ int request_timeout; /* Request timout in jiffies. */ struct timer_list timeout; /* Timer for request timeouts. */ struct list_head pendingq; /* List of message sent to AP queue. */ diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 731dc0dbfb75..0110d44172a3 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -63,13 +63,11 @@ static ssize_t ap_request_count_show(struct device *dev, char *buf) { struct ap_card *ac = to_ap_card(dev); - struct ap_queue *aq; unsigned int req_cnt; req_cnt = 0; spin_lock_bh(&ap_list_lock); - for_each_ap_queue(aq, ac) - req_cnt += aq->total_request_count; + req_cnt = atomic_read(&ac->total_request_count); spin_unlock_bh(&ap_list_lock); return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); } diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 8f95a071b670..b58a917dc510 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -625,6 +625,7 @@ void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg) list_add_tail(&ap_msg->list, &aq->requestq); aq->requestq_count++; aq->total_request_count++; + atomic_inc(&aq->card->total_request_count); /* Send/receive as many request from the queue as possible. */ ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL)); spin_unlock_bh(&aq->lock); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 403af9d1ebde..c7b5e70f2938 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -188,6 +188,34 @@ static inline void zcrypt_drop_queue(struct zcrypt_card *zc, module_put(mod); } +static inline bool zcrypt_card_compare(struct zcrypt_card *zc, + struct zcrypt_card *pref_zc, + unsigned weight, unsigned pref_weight) +{ + if (!pref_zc) + return 0; + weight += atomic_read(&zc->load); + pref_weight += atomic_read(&pref_zc->load); + if (weight == pref_weight) + return atomic_read(&zc->card->total_request_count) > + atomic_read(&pref_zc->card->total_request_count); + return weight > pref_weight; +} + +static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, + struct zcrypt_queue *pref_zq, + unsigned weight, unsigned pref_weight) +{ + if (!pref_zq) + return 0; + weight += atomic_read(&zq->load); + pref_weight += atomic_read(&pref_zq->load); + if (weight == pref_weight) + return &zq->queue->total_request_count > + &pref_zq->queue->total_request_count; + return weight > pref_weight; +} + /* * zcrypt ioctls. */ @@ -225,15 +253,14 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -289,15 +316,14 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -346,8 +372,7 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) continue; /* get weight index of the card device */ weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -355,8 +380,8 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) ((*domain != (unsigned short) AUTOSELECT) && (*domain != AP_QID_QUEUE(zq->queue->qid)))) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -450,8 +475,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) continue; /* get weight index of the card device */ weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -460,8 +484,8 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -510,15 +534,14 @@ static long zcrypt_rng(char *buffer) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; -- cgit v1.2.3 From 148784246ef2d85f000713cf56e1c90b405228e8 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 27 Oct 2016 08:57:39 +0200 Subject: s390/zcrypt: Correct function bits for CEX2x and CEX3x cards. For the older CEX2x and CEX3x cards the function bits returned by TAPQ do not reflect the functions of the card. Instead the functionality is implicit by the type of the card. The reworked zcrypt requires to have the function bits set correct, so this patch fixes this. The queue selection is not only based on these function bits but also on function pointers set by the individual drivers. Signed-off-by: Harald Freudenberger Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 17 +++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 8 +++++--- 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ac6c258300cf..b15013234c77 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -273,6 +273,23 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, nd = (info >> 16) & 0xff; if ((info & (1UL << 57)) && nd > 0) ap_max_domain_id = nd; + switch (*device_type) { + /* For CEX2 and CEX3 the available functions + * are not refrected by the facilities bits. + * Instead it is coded into the type. So here + * modify the function bits based on the type. + */ + case AP_DEVICE_TYPE_CEX2A: + case AP_DEVICE_TYPE_CEX3A: + *facilities |= 0x08000000; + break; + case AP_DEVICE_TYPE_CEX2C: + case AP_DEVICE_TYPE_CEX3C: + *facilities |= 0x10000000; + break; + default: + break; + } return 0; case AP_RESPONSE_Q_NOT_AVAIL: case AP_RESPONSE_DECONFIGURED: diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index c7b5e70f2938..71e298fe339f 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -257,7 +257,7 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ - if (!zq->online) + if (!zq->online || !zq->ops->rsa_modexpo) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) @@ -320,7 +320,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ - if (!zq->online) + if (!zq->online || !zq->ops->rsa_modexpo_crt) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) @@ -377,6 +377,7 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online || + !zq->ops->send_cprb || ((*domain != (unsigned short) AUTOSELECT) && (*domain != AP_QID_QUEUE(zq->queue->qid)))) continue; @@ -480,6 +481,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online || + !zq->ops->send_ep11_cprb || (targets && !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) @@ -538,7 +540,7 @@ static long zcrypt_rng(char *buffer) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ - if (!zq->online) + if (!zq->online || !zq->ops->rng) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) -- cgit v1.2.3 From c1c1368de497648cf532e7f37a407361c70aa638 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Wed, 2 Nov 2016 10:23:24 +0100 Subject: s390/zcrypt: Fix ap_max_domain_id for older machine types According to the system architecture the current implementation requires the presence of the N bit in GR2 in the TAPQ response field to validate the max. number of domains (Nd). Older machine types don't have this N bit, hence the max. domain field was ignored. Before the N bit was introduced the maximum number of domain was a constant value of 15. So set this value in case of N bit absence. Signed-off-by: Ingo Tuchscherer Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index b15013234c77..78c99ae42b1f 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -271,8 +271,11 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, *facilities = (unsigned int)(info >> 32); /* Update maximum domain id */ nd = (info >> 16) & 0xff; + /* if N bit is available, z13 and newer */ if ((info & (1UL << 57)) && nd > 0) ap_max_domain_id = nd; + else /* older machine types */ + ap_max_domain_id = 15; switch (*device_type) { /* For CEX2 and CEX3 the available functions * are not refrected by the facilities bits. -- cgit v1.2.3 From bf9f31190aa176c43c15cf58b60818d325e0f851 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Fri, 25 Nov 2016 11:50:16 +0100 Subject: s390/zcrypt: Improved invalid domain response handling. Add defines and switch case code to handle the two invalid domain response codes better. Until now these two response codes are handled via default resulting in -EAGAIN and switching the processed queue to offline. So this kind of malformed request bounced through all suitable queues and switched them off. Now this kind of malformed request is just rejected with EINVAL without switching off the queue. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_error.h | 62 ++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 09247331e9fb..865978879661 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -55,37 +55,39 @@ struct error_hdr { #define TYPE82_RSP_CODE 0x82 #define TYPE88_RSP_CODE 0x88 -#define REP82_ERROR_MACHINE_FAILURE 0x10 -#define REP82_ERROR_PREEMPT_FAILURE 0x12 -#define REP82_ERROR_CHECKPT_FAILURE 0x14 -#define REP82_ERROR_MESSAGE_TYPE 0x20 -#define REP82_ERROR_INVALID_COMM_CD 0x21 /* Type 84 */ -#define REP82_ERROR_INVALID_MSG_LEN 0x23 -#define REP82_ERROR_RESERVD_FIELD 0x24 /* was 0x50 */ -#define REP82_ERROR_FORMAT_FIELD 0x29 -#define REP82_ERROR_INVALID_COMMAND 0x30 -#define REP82_ERROR_MALFORMED_MSG 0x40 -#define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */ -#define REP82_ERROR_WORD_ALIGNMENT 0x60 -#define REP82_ERROR_MESSAGE_LENGTH 0x80 -#define REP82_ERROR_OPERAND_INVALID 0x82 -#define REP82_ERROR_OPERAND_SIZE 0x84 -#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85 -#define REP82_ERROR_RESERVED_FIELD 0x88 -#define REP82_ERROR_TRANSPORT_FAIL 0x90 -#define REP82_ERROR_PACKET_TRUNCATED 0xA0 -#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0 +#define REP82_ERROR_MACHINE_FAILURE 0x10 +#define REP82_ERROR_PREEMPT_FAILURE 0x12 +#define REP82_ERROR_CHECKPT_FAILURE 0x14 +#define REP82_ERROR_MESSAGE_TYPE 0x20 +#define REP82_ERROR_INVALID_COMM_CD 0x21 /* Type 84 */ +#define REP82_ERROR_INVALID_MSG_LEN 0x23 +#define REP82_ERROR_RESERVD_FIELD 0x24 /* was 0x50 */ +#define REP82_ERROR_FORMAT_FIELD 0x29 +#define REP82_ERROR_INVALID_COMMAND 0x30 +#define REP82_ERROR_MALFORMED_MSG 0x40 +#define REP82_ERROR_INVALID_DOMAIN_PRECHECK 0x42 +#define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */ +#define REP82_ERROR_WORD_ALIGNMENT 0x60 +#define REP82_ERROR_MESSAGE_LENGTH 0x80 +#define REP82_ERROR_OPERAND_INVALID 0x82 +#define REP82_ERROR_OPERAND_SIZE 0x84 +#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85 +#define REP82_ERROR_RESERVED_FIELD 0x88 +#define REP82_ERROR_INVALID_DOMAIN_PENDING 0x8A +#define REP82_ERROR_TRANSPORT_FAIL 0x90 +#define REP82_ERROR_PACKET_TRUNCATED 0xA0 +#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0 -#define REP88_ERROR_MODULE_FAILURE 0x10 +#define REP88_ERROR_MODULE_FAILURE 0x10 -#define REP88_ERROR_MESSAGE_TYPE 0x20 -#define REP88_ERROR_MESSAGE_MALFORMD 0x22 -#define REP88_ERROR_MESSAGE_LENGTH 0x23 -#define REP88_ERROR_RESERVED_FIELD 0x24 -#define REP88_ERROR_KEY_TYPE 0x34 -#define REP88_ERROR_INVALID_KEY 0x82 /* CEX2A */ -#define REP88_ERROR_OPERAND 0x84 /* CEX2A */ -#define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */ +#define REP88_ERROR_MESSAGE_TYPE 0x20 +#define REP88_ERROR_MESSAGE_MALFORMD 0x22 +#define REP88_ERROR_MESSAGE_LENGTH 0x23 +#define REP88_ERROR_RESERVED_FIELD 0x24 +#define REP88_ERROR_KEY_TYPE 0x34 +#define REP88_ERROR_INVALID_KEY 0x82 /* CEX2A */ +#define REP88_ERROR_OPERAND 0x84 /* CEX2A */ +#define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */ static inline int convert_error(struct zcrypt_queue *zq, struct ap_message *reply) @@ -97,6 +99,8 @@ static inline int convert_error(struct zcrypt_queue *zq, case REP82_ERROR_OPERAND_SIZE: case REP82_ERROR_EVEN_MOD_IN_OPND: case REP88_ERROR_MESSAGE_MALFORMD: + case REP82_ERROR_INVALID_DOMAIN_PRECHECK: + case REP82_ERROR_INVALID_DOMAIN_PENDING: // REP88_ERROR_INVALID_KEY // '82' CEX2A // REP88_ERROR_OPERAND // '84' CEX2A // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A -- cgit v1.2.3 From cccd85bfb7bf6787302435c669ceec23b5a5301c Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 24 Nov 2016 06:45:21 +0100 Subject: s390/zcrypt: Rework debug feature invocations. Rework the debug feature calls and initialization. There are now two debug feature entries used by the zcrypt code. The first is 'ap' with all the AP bus related stuff and the second is 'zcrypt' with all the zcrypt and devices and driver related entries. However, there isn't much traffic on both debug features. The ap bus code emits only some debug info and for zcrypt devices on appearance and disappearance there is an entry written. The new dbf invocations use the sprintf buffer layout, whereas the old implementation used the ascii dbf buffer. There are now 5*8=40 bytes used for each entry, resulting in 5 parameters per call. As the sprintf buffer needs a format string the first parameter provides this and so up to 4 more parameters can be used. Alltogehter the new layout should be much more human readable for customers and test. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 40 +++++++++++++++++ drivers/s390/crypto/ap_debug.h | 28 ++++++++++++ drivers/s390/crypto/zcrypt_api.c | 38 ++++++---------- drivers/s390/crypto/zcrypt_api.h | 8 ---- drivers/s390/crypto/zcrypt_card.c | 10 ++++- drivers/s390/crypto/zcrypt_debug.h | 50 ++++++--------------- drivers/s390/crypto/zcrypt_error.h | 35 ++++++++------- drivers/s390/crypto/zcrypt_msgtype50.c | 23 +++++----- drivers/s390/crypto/zcrypt_msgtype6.c | 80 +++++++++++++++++++--------------- drivers/s390/crypto/zcrypt_queue.c | 21 +++++---- 10 files changed, 190 insertions(+), 143 deletions(-) create mode 100644 drivers/s390/crypto/ap_debug.h (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 78c99ae42b1f..6d75984a3d85 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -47,9 +47,11 @@ #include #include #include +#include #include "ap_bus.h" #include "ap_asm.h" +#include "ap_debug.h" /* * Module description. @@ -81,6 +83,12 @@ LIST_HEAD(ap_card_list); static struct ap_config_info *ap_configuration; static bool initialised; +/* + * AP bus related debug feature things. + */ +static struct dentry *ap_dbf_root; +debug_info_t *ap_dbf_info; + /* * Workqueue timer for bus rescan. */ @@ -568,6 +576,8 @@ static int ap_dev_resume(struct device *dev) static void ap_bus_suspend(void) { + AP_DBF(DBF_DEBUG, "ap_bus_suspend running\n"); + ap_suspend_flag = 1; /* * Disable scanning for devices, thus we do not want to scan @@ -603,6 +613,8 @@ static void ap_bus_resume(void) { int rc; + AP_DBF(DBF_DEBUG, "ap_bus_resume running\n"); + /* remove all queue devices */ bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_queue_devices_unregister); @@ -742,6 +754,9 @@ static ssize_t ap_domain_store(struct bus_type *bus, spin_lock_bh(&ap_domain_lock); ap_domain_index = domain; spin_unlock_bh(&ap_domain_lock); + + AP_DBF(DBF_DEBUG, "store new default domain=%d\n", domain); + return count; } @@ -964,6 +979,8 @@ static void ap_scan_bus(struct work_struct *unused) unsigned int functions = 0; int rc, id, dom, borked, domains; + AP_DBF(DBF_DEBUG, "ap_scan_bus running\n"); + ap_query_configuration(); if (ap_select_domain() != 0) goto out; @@ -1129,6 +1146,23 @@ static struct reset_call ap_reset_call = { .fn = ap_reset_all, }; +int __init ap_debug_init(void) +{ + ap_dbf_root = debugfs_create_dir("ap", NULL); + ap_dbf_info = debug_register("ap", 1, 1, + DBF_MAX_SPRINTF_ARGS * sizeof(long)); + debug_register_view(ap_dbf_info, &debug_sprintf_view); + debug_set_level(ap_dbf_info, DBF_ERR); + + return 0; +} + +void ap_debug_exit(void) +{ + debugfs_remove(ap_dbf_root); + debug_unregister(ap_dbf_info); +} + /** * ap_module_init(): The module initialization code. * @@ -1139,6 +1173,10 @@ int __init ap_module_init(void) int max_domain_id; int rc, i; + rc = ap_debug_init(); + if (rc) + return rc; + if (ap_instructions_available() != 0) { pr_warn("The hardware system does not support AP instructions\n"); return -ENODEV; @@ -1266,6 +1304,8 @@ void ap_module_exit(void) unregister_reset_call(&ap_reset_call); if (ap_using_interrupts()) unregister_adapter_interrupt(&ap_airq); + + ap_debug_exit(); } module_init(ap_module_init); diff --git a/drivers/s390/crypto/ap_debug.h b/drivers/s390/crypto/ap_debug.h new file mode 100644 index 000000000000..78dbff842dae --- /dev/null +++ b/drivers/s390/crypto/ap_debug.h @@ -0,0 +1,28 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Harald Freudenberger + */ +#ifndef AP_DEBUG_H +#define AP_DEBUG_H + +#include + +#define DBF_ERR 3 /* error conditions */ +#define DBF_WARN 4 /* warning conditions */ +#define DBF_INFO 5 /* informational */ +#define DBF_DEBUG 6 /* for debugging only */ + +#define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO) +#define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO) + +#define DBF_MAX_SPRINTF_ARGS 5 + +#define AP_DBF(...) \ + debug_sprintf_event(ap_dbf_info, ##__VA_ARGS__) + +extern debug_info_t *ap_dbf_info; + +int ap_debug_init(void); +void ap_debug_exit(void); + +#endif /* AP_DEBUG_H */ diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 71e298fe339f..7ca25e77bd6a 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -41,8 +41,8 @@ #include #include -#include "zcrypt_debug.h" #include "zcrypt_api.h" +#include "zcrypt_debug.h" #include "zcrypt_msgtype6.h" #include "zcrypt_msgtype50.h" @@ -71,10 +71,9 @@ EXPORT_SYMBOL(zcrypt_rescan_req); static LIST_HEAD(zcrypt_ops_list); -static struct dentry *debugfs_root; -debug_info_t *zcrypt_dbf_common; -debug_info_t *zcrypt_dbf_devices; -debug_info_t *zcrypt_dbf_cards; +/* Zcrypt related debug feature stuff. */ +static struct dentry *zcrypt_dbf_root; +debug_info_t *zcrypt_dbf_info; /** * Process a rescan of the transport layer. @@ -87,8 +86,8 @@ static inline int zcrypt_process_rescan(void) atomic_set(&zcrypt_rescan_req, 0); atomic_inc(&zcrypt_rescan_count); ap_bus_force_rescan(); - ZCRYPT_DBF_COMMON(DBF_INFO, "rescan%07d", - atomic_inc_return(&zcrypt_rescan_count)); + ZCRYPT_DBF(DBF_INFO, "rescan count=%07d", + atomic_inc_return(&zcrypt_rescan_count)); return 1; } return 0; @@ -1363,28 +1362,19 @@ void zcrypt_rng_device_remove(void) int __init zcrypt_debug_init(void) { - debugfs_root = debugfs_create_dir("zcrypt", NULL); - - zcrypt_dbf_common = debug_register("zcrypt_common", 1, 1, 16); - debug_register_view(zcrypt_dbf_common, &debug_hex_ascii_view); - debug_set_level(zcrypt_dbf_common, DBF_ERR); - - zcrypt_dbf_devices = debug_register("zcrypt_devices", 1, 1, 16); - debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view); - debug_set_level(zcrypt_dbf_devices, DBF_ERR); - - zcrypt_dbf_cards = debug_register("zcrypt_cards", 1, 1, 16); - debug_register_view(zcrypt_dbf_cards, &debug_hex_ascii_view); - debug_set_level(zcrypt_dbf_cards, DBF_ERR); + zcrypt_dbf_root = debugfs_create_dir("zcrypt", NULL); + zcrypt_dbf_info = debug_register("zcrypt", 1, 1, + DBF_MAX_SPRINTF_ARGS * sizeof(long)); + debug_register_view(zcrypt_dbf_info, &debug_sprintf_view); + debug_set_level(zcrypt_dbf_info, DBF_ERR); return 0; } void zcrypt_debug_exit(void) { - debugfs_remove(debugfs_root); - debug_unregister(zcrypt_dbf_common); - debug_unregister(zcrypt_dbf_devices); + debugfs_remove(zcrypt_dbf_root); + debug_unregister(zcrypt_dbf_info); } /** @@ -1434,9 +1424,9 @@ 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(); + zcrypt_debug_exit(); } module_init(zcrypt_api_init); diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 4fb892b99f41..274a59051534 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -132,8 +132,6 @@ struct zcrypt_card { atomic_t load; /* Utilization of the crypto device */ int request_count; /* # current requests. */ - - debug_info_t *dbf_area; /* debugging */ }; struct zcrypt_queue { @@ -149,8 +147,6 @@ struct zcrypt_queue { int request_count; /* # current requests. */ struct ap_message reply; /* Per-device reply structure. */ - - debug_info_t *dbf_area; /* debugging */ }; /* transport layer rescanning */ @@ -160,10 +156,6 @@ extern spinlock_t zcrypt_list_lock; extern int zcrypt_device_count; extern struct list_head zcrypt_card_list; -extern debug_info_t *zcrypt_dbf_common; -extern debug_info_t *zcrypt_dbf_devices; -extern debug_info_t *zcrypt_dbf_cards; - #define for_each_zcrypt_card(_zc) \ list_for_each_entry(_zc, &zcrypt_card_list, list) diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index 57873d775e95..53436ea52230 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -79,7 +79,9 @@ static ssize_t zcrypt_card_online_store(struct device *dev, zc->online = online; id = zc->card->id; - ZCRYPT_DBF_DEV(DBF_INFO, zc, "card%02xo%dman", id, online); + + ZCRYPT_DBF(DBF_INFO, "card=%02x online=%d\n", id, online); + spin_lock(&zcrypt_list_lock); list_for_each_entry(zq, &zc->zqueues, list) zcrypt_queue_force_online(zq, online); @@ -109,7 +111,6 @@ struct zcrypt_card *zcrypt_card_alloc(void) return NULL; INIT_LIST_HEAD(&zc->list); INIT_LIST_HEAD(&zc->zqueues); - zc->dbf_area = zcrypt_dbf_cards; kref_init(&zc->refcount); return zc; } @@ -160,6 +161,9 @@ int zcrypt_card_register(struct zcrypt_card *zc) spin_unlock(&zcrypt_list_lock); zc->online = 1; + + ZCRYPT_DBF(DBF_INFO, "card=%02x register online=1\n", zc->card->id); + return rc; } EXPORT_SYMBOL(zcrypt_card_register); @@ -172,6 +176,8 @@ EXPORT_SYMBOL(zcrypt_card_register); */ void zcrypt_card_unregister(struct zcrypt_card *zc) { + ZCRYPT_DBF(DBF_INFO, "card=%02x unregister\n", zc->card->id); + spin_lock(&zcrypt_list_lock); list_del_init(&zc->list); spin_unlock(&zcrypt_list_lock); diff --git a/drivers/s390/crypto/zcrypt_debug.h b/drivers/s390/crypto/zcrypt_debug.h index 28d9349de1ad..13e38defb6b8 100644 --- a/drivers/s390/crypto/zcrypt_debug.h +++ b/drivers/s390/crypto/zcrypt_debug.h @@ -1,51 +1,27 @@ /* - * Copyright IBM Corp. 2012 + * Copyright IBM Corp. 2016 * Author(s): Holger Dengler (hd@linux.vnet.ibm.com) + * Harald Freudenberger */ #ifndef ZCRYPT_DEBUG_H #define ZCRYPT_DEBUG_H #include -#include "zcrypt_api.h" -/* that gives us 15 characters in the text event views */ -#define ZCRYPT_DBF_LEN 16 - -#define DBF_ERR 3 /* error conditions */ -#define DBF_WARN 4 /* warning conditions */ -#define DBF_INFO 6 /* informational */ +#define DBF_ERR 3 /* error conditions */ +#define DBF_WARN 4 /* warning conditions */ +#define DBF_INFO 5 /* informational */ +#define DBF_DEBUG 6 /* for debugging only */ +#define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO) #define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO) -#define ZCRYPT_DBF_COMMON(level, text...) \ - do { \ - if (debug_level_enabled(zcrypt_dbf_common, level)) { \ - char debug_buffer[ZCRYPT_DBF_LEN]; \ - snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ - debug_text_event(zcrypt_dbf_common, level, \ - debug_buffer); \ - } \ - } while (0) - -#define ZCRYPT_DBF_DEVICES(level, text...) \ - do { \ - if (debug_level_enabled(zcrypt_dbf_devices, level)) { \ - char debug_buffer[ZCRYPT_DBF_LEN]; \ - snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ - debug_text_event(zcrypt_dbf_devices, level, \ - debug_buffer); \ - } \ - } while (0) - -#define ZCRYPT_DBF_DEV(level, device, text...) \ - do { \ - if (debug_level_enabled(device->dbf_area, level)) { \ - char debug_buffer[ZCRYPT_DBF_LEN]; \ - snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ - debug_text_event(device->dbf_area, level, \ - debug_buffer); \ - } \ - } while (0) +#define DBF_MAX_SPRINTF_ARGS 5 + +#define ZCRYPT_DBF(...) \ + debug_sprintf_event(zcrypt_dbf_info, ##__VA_ARGS__) + +extern debug_info_t *zcrypt_dbf_info; int zcrypt_debug_init(void); void zcrypt_debug_exit(void); diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 865978879661..13df60209ed3 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -93,6 +93,8 @@ static inline int convert_error(struct zcrypt_queue *zq, struct ap_message *reply) { struct error_hdr *ehdr = reply->message; + int card = AP_QID_CARD(zq->queue->qid); + int queue = AP_QID_QUEUE(zq->queue->qid); switch (ehdr->reply_code) { case REP82_ERROR_OPERAND_INVALID: @@ -105,6 +107,9 @@ static inline int convert_error(struct zcrypt_queue *zq, // REP88_ERROR_OPERAND // '84' CEX2A // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A /* Invalid input data. */ + ZCRYPT_DBF(DBF_WARN, + "device=%02x.%04x reply=0x%02x => rc=EINVAL\n", + card, queue, ehdr->reply_code); return -EINVAL; case REP82_ERROR_MESSAGE_TYPE: // REP88_ERROR_MESSAGE_TYPE // '20' CEX2A @@ -116,12 +121,10 @@ static inline int convert_error(struct zcrypt_queue *zq, atomic_set(&zcrypt_rescan_req, 1); zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), zq->online, - ehdr->reply_code); + card, queue); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n", + card, queue, ehdr->reply_code); return -EAGAIN; case REP82_ERROR_TRANSPORT_FAIL: case REP82_ERROR_MACHINE_FAILURE: @@ -130,22 +133,18 @@ static inline int convert_error(struct zcrypt_queue *zq, atomic_set(&zcrypt_rescan_req, 1); zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), zq->online, - ehdr->reply_code); + card, queue); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n", + card, queue, ehdr->reply_code); return -EAGAIN; default: zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), zq->online, - ehdr->reply_code); + card, queue); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n", + card, queue, ehdr->reply_code); return -EAGAIN; /* repeat the request on a different device. */ } } diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index a9873b436115..6dd5d7c58dd0 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -367,11 +367,11 @@ static int convert_type80(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online, t80h->code); - + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x code=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + t80h->code); return -EAGAIN; /* repeat the request on a different device. */ } if (zq->zcard->user_space_type == ZCRYPT_CEX2A) @@ -390,7 +390,9 @@ static int convert_response(struct zcrypt_queue *zq, unsigned int outputdatalength) { /* Response type byte is the second byte in the response. */ - switch (((unsigned char *) reply->message)[1]) { + unsigned char rtype = ((unsigned char *) reply->message)[1]; + + switch (rtype) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: return convert_error(zq, reply); @@ -402,10 +404,11 @@ static int convert_response(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (unsigned int) rtype); return -EAGAIN; /* repeat the request on a different device. */ } } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index c6cfb9acec19..e5563ffeb839 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -638,30 +638,37 @@ static int convert_type86_ica(struct zcrypt_queue *zq, service_rc = msg->cprbx.ccp_rtcode; if (unlikely(service_rc != 0)) { service_rs = msg->cprbx.ccp_rscode; - if (service_rc == 8 && service_rs == 66) - return -EINVAL; - if (service_rc == 8 && service_rs == 65) - return -EINVAL; - if (service_rc == 8 && service_rs == 770) + if ((service_rc == 8 && service_rs == 66) || + (service_rc == 8 && service_rs == 65) || + (service_rc == 8 && service_rs == 72) || + (service_rc == 8 && service_rs == 770) || + (service_rc == 12 && service_rs == 769)) { + ZCRYPT_DBF(DBF_DEBUG, + "device=%02x.%04x rc/rs=%d/%d => rc=EINVAL\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) service_rc, (int) service_rs); return -EINVAL; + } if (service_rc == 8 && service_rs == 783) { zq->zcard->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; + ZCRYPT_DBF(DBF_DEBUG, + "device=%02x.%04x rc/rs=%d/%d => rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) service_rc, (int) service_rs); return -EAGAIN; } - if (service_rc == 12 && service_rs == 769) - return -EINVAL; - if (service_rc == 8 && service_rs == 72) - return -EINVAL; zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online, - msg->hdr.reply_code); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rc/rs=%d/%d => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) service_rc, (int) service_rs); return -EAGAIN; /* repeat the request on a different device. */ } data = msg->text; @@ -776,8 +783,7 @@ static int convert_response_ica(struct zcrypt_queue *zq, { struct type86x_reply *msg = reply->message; - /* Response type byte is the second byte in the response. */ - switch (((unsigned char *) reply->message)[1]) { + switch (msg->hdr.type) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: return convert_error(zq, reply); @@ -803,10 +809,11 @@ static int convert_response_ica(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -817,8 +824,7 @@ static int convert_response_xcrb(struct zcrypt_queue *zq, { struct type86x_reply *msg = reply->message; - /* Response type byte is the second byte in the response. */ - switch (((unsigned char *) reply->message)[1]) { + switch (msg->hdr.type) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ @@ -838,10 +844,11 @@ static int convert_response_xcrb(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -851,8 +858,7 @@ static int convert_response_ep11_xcrb(struct zcrypt_queue *zq, { struct type86_ep11_reply *msg = reply->message; - /* Response type byte is the second byte in the response. */ - switch (((unsigned char *)reply->message)[1]) { + switch (msg->hdr.type) { case TYPE82_RSP_CODE: case TYPE87_RSP_CODE: return convert_error(zq, reply); @@ -867,10 +873,11 @@ static int convert_response_ep11_xcrb(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -897,10 +904,11 @@ static int convert_response_rng(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index c70b2528d9a3..a303f3b2c328 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -70,9 +70,12 @@ static ssize_t zcrypt_queue_online_store(struct device *dev, if (online && !zc->online) return -EINVAL; zq->online = online; - ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dman", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), online); + + ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x online=%d\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + online); + if (!online) ap_flush_queue(zq->queue); return count; @@ -109,7 +112,6 @@ struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size) goto out_free; zq->reply.length = max_response_size; INIT_LIST_HEAD(&zq->list); - zq->dbf_area = zcrypt_dbf_devices; kref_init(&zq->refcount); return zq; @@ -161,10 +163,10 @@ int zcrypt_queue_register(struct zcrypt_queue *zq) zcrypt_card_get(zc); zq->zcard = zc; zq->online = 1; /* New devices are online by default. */ - ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dreg", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + + ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x register online=1\n", + AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); + list_add_tail(&zq->list, &zc->zqueues); zcrypt_device_count++; spin_unlock(&zcrypt_list_lock); @@ -205,6 +207,9 @@ void zcrypt_queue_unregister(struct zcrypt_queue *zq) { struct zcrypt_card *zc; + ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x unregister\n", + AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); + zc = zq->zcard; spin_lock(&zcrypt_list_lock); list_del_init(&zq->list); -- cgit v1.2.3 From 13b251bdc8b97c45cc8b1d57193ab05ec0fe97e8 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Fri, 25 Nov 2016 18:04:56 +0100 Subject: s390/zcrypt: tracepoint definitions for zcrypt device driver. This patch introduces tracepoint definitions and tracepoint event invocations for the s390 zcrypt device. Currently there are just two tracepoint events defined. An s390_zcrypt_req request event occurs as soon as the request is recognized by the zcrypt ioctl function. This event may act as some kind of request-processing-starts-now indication. As late as possible within the zcrypt ioctl function there occurs the s390_zcrypt_rep event which may act as the point in time where the request has been processed by the kernel and the result is about to be transferred back to userspace. The glue which binds together request and reply event is the ptr parameter, which is the local buffer address where the request from userspace has been stored by the ioctl function. The main purpose of this zcrypt tracepoint patch is to get some data for performance measurements together with information about the kind of request and on which card and queue the request has been processed. It is not an ffdc interface as there is already code in the zcrypt device driver to serve the s390 debug feature interface. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/trace/zcrypt.h | 122 +++++++++++++++++++++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 105 +++++++++++++++++++++++------- 2 files changed, 203 insertions(+), 24 deletions(-) create mode 100644 arch/s390/include/asm/trace/zcrypt.h (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/trace/zcrypt.h b/arch/s390/include/asm/trace/zcrypt.h new file mode 100644 index 000000000000..adcb77fafa9d --- /dev/null +++ b/arch/s390/include/asm/trace/zcrypt.h @@ -0,0 +1,122 @@ +/* + * Tracepoint definitions for the s390 zcrypt device driver + * + * Copyright IBM Corp. 2016 + * Author(s): Harald Freudenberger + * + * Currently there are two tracepoint events defined here. + * An s390_zcrypt_req request event occurs as soon as the request is + * recognized by the zcrypt ioctl function. This event may act as some kind + * of request-processing-starts-now indication. + * As late as possible within the zcrypt ioctl function there occurs the + * s390_zcrypt_rep event which may act as the point in time where the + * request has been processed by the kernel and the result is about to be + * transferred back to userspace. + * The glue which binds together request and reply event is the ptr + * parameter, which is the local buffer address where the request from + * userspace has been stored by the ioctl function. + * + * The main purpose of this zcrypt tracepoint api is to get some data for + * performance measurements together with information about on which card + * and queue the request has been processed. It is not an ffdc interface as + * there is already code in the zcrypt device driver to serve the s390 + * debug feature interface. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM s390 + +#if !defined(_TRACE_S390_ZCRYPT_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_S390_ZCRYPT_H + +#include + +#define TP_ICARSAMODEXPO 0x0001 +#define TP_ICARSACRT 0x0002 +#define TB_ZSECSENDCPRB 0x0003 +#define TP_ZSENDEP11CPRB 0x0004 +#define TP_HWRNGCPRB 0x0005 + +#define show_zcrypt_tp_type(type) \ + __print_symbolic(type, \ + { TP_ICARSAMODEXPO, "ICARSAMODEXPO" }, \ + { TP_ICARSACRT, "ICARSACRT" }, \ + { TB_ZSECSENDCPRB, "ZSECSENDCPRB" }, \ + { TP_ZSENDEP11CPRB, "ZSENDEP11CPRB" }, \ + { TP_HWRNGCPRB, "HWRNGCPRB" }) + +/** + * trace_s390_zcrypt_req - zcrypt request tracepoint function + * @ptr: Address of the local buffer where the request from userspace + * is stored. Can be used as a unique id to relate together + * request and reply. + * @type: One of the TP_ defines above. + * + * Called when a request from userspace is recognised within the ioctl + * function of the zcrypt device driver and may act as an entry + * timestamp. + */ +TRACE_EVENT(s390_zcrypt_req, + TP_PROTO(void *ptr, u32 type), + TP_ARGS(ptr, type), + TP_STRUCT__entry( + __field(void *, ptr) + __field(u32, type)), + TP_fast_assign( + __entry->ptr = ptr; + __entry->type = type;), + TP_printk("ptr=%p type=%s", + __entry->ptr, + show_zcrypt_tp_type(__entry->type)) +); + +/** + * trace_s390_zcrypt_rep - zcrypt reply tracepoint function + * @ptr: Address of the local buffer where the request from userspace + * is stored. Can be used as a unique id to match together + * request and reply. + * @fc: Function code. + * @rc: The bare returncode as returned by the device driver ioctl + * function. + * @dev: The adapter nr where this request was actually processed. + * @dom: Domain id of the device where this request was processed. + * + * Called upon recognising the reply from the crypto adapter. This + * message may act as the exit timestamp for the request but also + * carries some info about on which adapter the request was processed + * and the returncode from the device driver. + */ +TRACE_EVENT(s390_zcrypt_rep, + TP_PROTO(void *ptr, u32 fc, u32 rc, u16 dev, u16 dom), + TP_ARGS(ptr, fc, rc, dev, dom), + TP_STRUCT__entry( + __field(void *, ptr) + __field(u32, fc) + __field(u32, rc) + __field(u16, device) + __field(u16, domain)), + TP_fast_assign( + __entry->ptr = ptr; + __entry->fc = fc; + __entry->rc = rc; + __entry->device = dev; + __entry->domain = dom;), + TP_printk("ptr=%p fc=0x%04x rc=%d dev=0x%02hx domain=0x%04hx", + __entry->ptr, + (unsigned int) __entry->fc, + (int) __entry->rc, + (unsigned short) __entry->device, + (unsigned short) __entry->domain) +); + +#endif /* _TRACE_S390_ZCRYPT_H */ + +/* This part must be outside protection */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE + +#define TRACE_INCLUDE_PATH asm/trace +#define TRACE_INCLUDE_FILE zcrypt + +#include diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 7ca25e77bd6a..854a6e58dfea 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -41,6 +41,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include "zcrypt_api.h" #include "zcrypt_debug.h" @@ -55,6 +58,12 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); +/* + * zcrypt tracepoint functions + */ +EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_req); +EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_rep); + static int zcrypt_hwrng_seed = 1; module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on)."); @@ -224,10 +233,15 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) struct zcrypt_queue *zq, *pref_zq; unsigned int weight, pref_weight; unsigned int func_code; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO); + + if (mex->outputdatalength < mex->inputdatalength) { + rc = -EINVAL; + goto out; + } - if (mex->outputdatalength < mex->inputdatalength) - return -EINVAL; /* * As long as outputdatalength is big enough, we can set the * outputdatalength equal to the inputdatalength, since that is the @@ -237,7 +251,7 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) rc = get_rsa_modex_fc(mex, &func_code); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -269,15 +283,21 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); - if (!pref_zq) - return -ENODEV; + if (!pref_zq) { + rc = -ENODEV; + goto out; + } + qid = pref_zq->queue->qid; rc = pref_zq->ops->rsa_modexpo(pref_zq, mex); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); +out: + trace_s390_zcrypt_rep(mex, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -287,10 +307,15 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) struct zcrypt_queue *zq, *pref_zq; unsigned int weight, pref_weight; unsigned int func_code; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(crt, TP_ICARSACRT); + + if (crt->outputdatalength < crt->inputdatalength) { + rc = -EINVAL; + goto out; + } - if (crt->outputdatalength < crt->inputdatalength) - return -EINVAL; /* * As long as outputdatalength is big enough, we can set the * outputdatalength equal to the inputdatalength, since that is the @@ -300,7 +325,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) rc = get_rsa_crt_fc(crt, &func_code); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -332,15 +357,21 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); - if (!pref_zq) - return -ENODEV; + if (!pref_zq) { + rc = -ENODEV; + goto out; + } + qid = pref_zq->queue->qid; rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); +out: + trace_s390_zcrypt_rep(crt, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -352,11 +383,13 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) unsigned int weight, pref_weight; unsigned int func_code; unsigned short *domain; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -391,18 +424,25 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); - if (!pref_zq) - return -ENODEV; + if (!pref_zq) { + rc = -ENODEV; + goto out; + } /* in case of auto select, provide the correct domain */ + qid = pref_zq->queue->qid; if (*domain == (unsigned short) AUTOSELECT) - *domain = AP_QID_QUEUE(pref_zq->queue->qid); + *domain = AP_QID_QUEUE(qid); rc = pref_zq->ops->send_cprb(pref_zq, xcRB, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); + +out: + trace_s390_zcrypt_rep(xcRB, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -439,7 +479,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) unsigned int weight, pref_weight; unsigned int func_code; struct ap_message ap_msg; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB); target_num = (unsigned short) xcrb->targets_num; @@ -449,13 +491,17 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) struct ep11_target_dev __user *uptr; targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL); - if (!targets) - return -ENOMEM; + if (!targets) { + rc = -ENOMEM; + goto out; + } uptr = (struct ep11_target_dev __force __user *) xcrb->targets; if (copy_from_user(targets, uptr, - target_num * sizeof(*targets))) - return -EFAULT; + target_num * sizeof(*targets))) { + rc = -EFAULT; + goto out; + } } rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); @@ -501,6 +547,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) goto out_free; } + qid = pref_zq->queue->qid; rc = pref_zq->ops->send_ep11_cprb(pref_zq, xcrb, &ap_msg); spin_lock(&zcrypt_list_lock); @@ -509,6 +556,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) out_free: kfree(targets); +out: + trace_s390_zcrypt_rep(xcrb, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -520,11 +570,13 @@ static long zcrypt_rng(char *buffer) unsigned int func_code; struct ap_message ap_msg; unsigned int domain; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB); rc = get_rng_fc(&ap_msg, &func_code, &domain); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -555,11 +607,16 @@ static long zcrypt_rng(char *buffer) if (!pref_zq) return -ENODEV; + qid = pref_zq->queue->qid; rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); + +out: + trace_s390_zcrypt_rep(buffer, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } -- cgit v1.2.3 From 50cff5adcf8eb8bcdd79087a91878f298fb58dcf Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 18 Nov 2016 14:39:05 +0100 Subject: s390/dasd: fix typos in DASD error messages Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_3990_erp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 95f7645e3c37..774da20ceb58 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -674,7 +674,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) break; case 0x0D: dev_warn(&device->cdev->dev, - "FORMAT 4 - No syn byte in count " + "FORMAT 4 - No sync byte in count " "address area; offset active\n"); break; case 0x0E: @@ -684,7 +684,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) break; case 0x0F: dev_warn(&device->cdev->dev, - "FORMAT 4 - No syn byte in data area; " + "FORMAT 4 - No sync byte in data area; " "offset active\n"); break; default: @@ -999,7 +999,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) break; default: dev_warn(&device->cdev->dev, - "FORMAT D - Reserved\n"); + "FORMAT F - Reserved\n"); } break; -- cgit v1.2.3 From d03502684b65492339d70f11aa8ed6df3961a3bf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 13 Dec 2016 13:24:03 +0100 Subject: s390/zcrypt: add missing memory clobber to ap_qci inline assembly The ap_qci() inline assembly writes to memory (*config) but misses to tell the compiler about it. Add the missing memory clobber to fix this. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_asm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_asm.h b/drivers/s390/crypto/ap_asm.h index 12fffdd1e8e8..7a630047c372 100644 --- a/drivers/s390/crypto/ap_asm.h +++ b/drivers/s390/crypto/ap_asm.h @@ -108,7 +108,7 @@ static inline int ap_qci(void *config) EX_TABLE(0b, 1b) : "+d" (reg0), "+d" (reg1), "+d" (reg2) : - : "cc"); + : "cc", "memory"); return reg1; } -- cgit v1.2.3