s390/zcrypt: Number of supported ap domains is not retrievable.
authorIngo Tuchscherer <ingo.tuchscherer@de.ibm.com>
Fri, 23 Jan 2015 12:27:04 +0000 (13:27 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 23 Jan 2015 14:17:10 +0000 (15:17 +0100)
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 <ingo.tuchscherer@de.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/crypto/ap_bus.c

index 4d41bf75c23318577638fa45493aab748e0473a7..faa058016b5ca777a7104dbc4090d6903c614857 100644 (file)
@@ -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.
  *