aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/crypto/ap_card.c
diff options
context:
space:
mode:
authorIngo Tuchscherer2016-08-25 11:16:03 +0200
committerMartin Schwidefsky2016-12-14 16:33:38 +0100
commite28d2af43614eb86f59812e7221735fc221bbc10 (patch)
tree20b54a9ac5121a82066098f287e5406efba2022c /drivers/s390/crypto/ap_card.c
parent34a15167739412750846d4f1a5540d9e592fd815 (diff)
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 <xx>.<yyyy> -> ../../../devices/ap/card<xx>/<xx>.<yyyy> ... card<xx> -> ../../../devices/ap/card<xx> ... drivers <drv>card card<xx> -> ../../../../devices/ap/card<xx> <drv>queue <xx>.<yyyy> -> ../../../../devices/ap/card<xx>/<xx>.<yyyy> ... /sys/devices/ap card<xx> <xx>.<yyyy> driver -> ../../../../bus/ap/drivers/<zzz>queue ... driver -> ../../../bus/ap/drivers/<drv>card ... The two digit <xx> field is the card number, the four digit <yyyy> field is the queue number and <drv> is the name of the device driver, e.g. "cex4". For compatability /sys/bus/ap/card<xx> 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 <ingo.tuchscherer@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/crypto/ap_card.c')
-rw-r--r--drivers/s390/crypto/ap_card.c172
1 files changed, 172 insertions, 0 deletions
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 <schwidefsky@de.ibm.com>
+ *
+ * Adjunct processor bus, card related code.
+ */
+
+#define KMSG_COMPONENT "ap"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/facility.h>
+
+#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;
+}