aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto/zcrypt_cex2a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto/zcrypt_cex2a.c')
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c214
1 files changed, 150 insertions, 64 deletions
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 15104aaa075a..c7d48a18199e 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/atomic.h>
#include <asm/uaccess.h>
+#include <linux/mod_devicetable.h>
#include "ap_bus.h"
#include "zcrypt_api.h"
@@ -43,9 +44,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 */
@@ -57,107 +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;
+ /*
+ * 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;
- zdev->speed_rating = CEX2A_SPEED_RATING;
- 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;
- zdev->speed_rating = CEX3A_SPEED_RATING;
break;
}
- if (!zdev)
+ if (!zq)
return -ENODEV;
- zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME,
- MSGTYPE50_VARIANT_DEFAULT);
- zdev->ap_dev = ap_dev;
- zdev->online = 1;
- 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_msgtype_release(zdev->ops);
- 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 zcrypt_ops *zops = zdev->ops;
+ struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+ struct zcrypt_queue *zq = aq->private;
- zcrypt_device_unregister(zdev);
- zcrypt_msgtype_release(zops);
+ 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);