From 5bc334bff9a6e189113140ed6dce0ce61d768943 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Fri, 23 Jan 2015 13:27:04 +0100 Subject: [PATCH] s390/zcrypt: Number of supported ap domains is not retrievable. Upcoming versions of secure key management facilities (CCA and EP11) require information about the maximum number of supported ap domains in order to service TKE requests properly. With IBM z13 the number of available domains (so far 16) has increased up to 85. This number varies depending on machine types and models. Therefore the new sysfs attribute 'ap_max_domain_id' provides this limit of supported ap domains. Upcoming releases for CCA and EP11 will use this new information. Without this problem fix it is not possible to retrieve reliable information about the maximum number of supported ap domains. Thus, customers are not able to perform key management for CCA and EP11 coprocessor adapters. Signed-off-by: Ingo Tuchscherer Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 137 ++++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 41 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 4d41bf75c233..faa058016b5c 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -203,6 +203,24 @@ ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type) return reg1; } +/** + * ap_query_facilities(): PQAP(TAPQ) query facilities. + * @qid: The AP queue number + * + * Returns content of general register 2 after the PQAP(TAPQ) + * instruction was called. + */ +static inline unsigned long ap_query_facilities(ap_qid_t qid) +{ + register unsigned long reg0 asm ("0") = qid | 0x00800000UL; + register unsigned long reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ + : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + return reg2; +} + /** * ap_reset_queue(): Reset adjunct processor queue. * @qid: The AP queue number @@ -1006,6 +1024,47 @@ void ap_bus_force_rescan(void) } EXPORT_SYMBOL(ap_bus_force_rescan); +/* + * ap_test_config(): helper function to extract the nrth bit + * within the unsigned int array field. + */ +static inline int ap_test_config(unsigned int *field, unsigned int nr) +{ + if (nr > 0xFFu) + return 0; + return ap_test_bit((field + (nr >> 5)), (nr & 0x1f)); +} + +/* + * ap_test_config_card_id(): Test, whether an AP card ID is configured. + * @id AP card ID + * + * Returns 0 if the card is not configured + * 1 if the card is configured or + * if the configuration information is not available + */ +static inline int ap_test_config_card_id(unsigned int id) +{ + if (!ap_configuration) + return 1; + return ap_test_config(ap_configuration->apm, id); +} + +/* + * ap_test_config_domain(): Test, whether an AP usage domain is configured. + * @domain AP usage domain ID + * + * Returns 0 if the usage domain is not configured + * 1 if the usage domain is configured or + * if the configuration information is not available + */ +static inline int ap_test_config_domain(unsigned int domain) +{ + if (!ap_configuration) + return 1; + return ap_test_config(ap_configuration->aqm, domain); +} + /* * AP bus attributes. */ @@ -1121,6 +1180,42 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); +static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) +{ + ap_qid_t qid; + int i, nd, max_domain_id = -1; + unsigned long fbits; + + if (ap_configuration) { + if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS) { + for (i = 0; i < AP_DEVICES; i++) { + if (!ap_test_config_card_id(i)) + continue; + qid = AP_MKQID(i, ap_domain_index); + fbits = ap_query_facilities(qid); + if (fbits & (1UL << 57)) { + /* the N bit is 0, Nd field is filled */ + nd = (int)((fbits & 0x00FF0000UL)>>16); + if (nd > 0) + max_domain_id = nd; + else + max_domain_id = 15; + } else { + /* N bit is 1, max 16 domains */ + max_domain_id = 15; + } + break; + } + } + } else { + /* no APXA support, older machines with max 16 domains */ + max_domain_id = 15; + } + return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id); +} + +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, @@ -1128,50 +1223,10 @@ static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_poll_thread, &bus_attr_ap_interrupts, &bus_attr_poll_timeout, + &bus_attr_ap_max_domain_id, NULL, }; -static inline int ap_test_config(unsigned int *field, unsigned int nr) -{ - if (nr > 0xFFu) - return 0; - return ap_test_bit((field + (nr >> 5)), (nr & 0x1f)); -} - -/* - * ap_test_config_card_id(): Test, whether an AP card ID is configured. - * @id AP card ID - * - * Returns 0 if the card is not configured - * 1 if the card is configured or - * if the configuration information is not available - */ -static inline int ap_test_config_card_id(unsigned int id) -{ - if (!ap_configuration) - return 1; - return ap_test_config(ap_configuration->apm, id); -} - -/* - * ap_test_config_domain(): Test, whether an AP usage domain is configured. - * @domain AP usage domain ID - * - * Returns 0 if the usage domain is not configured - * 1 if the usage domain is configured or - * if the configuration information is not available - */ -static inline int ap_test_config_domain(unsigned int domain) -{ - if (!ap_configuration) /* QCI not supported */ - if (domain < 16) - return 1; /* then domains 0...15 are configured */ - else - return 0; - else - return ap_test_config(ap_configuration->aqm, domain); -} - /** * ap_query_configuration(): Query AP configuration information. *