|  | /* | 
|  | *  Copyright IBM Corp. 2012 | 
|  | *  Author(s): Holger Dengler <hd@linux.vnet.ibm.com> | 
|  | */ | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <linux/slab.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/err.h> | 
|  | #include <linux/atomic.h> | 
|  | #include <linux/uaccess.h> | 
|  |  | 
|  | #include "ap_bus.h" | 
|  | #include "zcrypt_api.h" | 
|  | #include "zcrypt_msgtype6.h" | 
|  | #include "zcrypt_msgtype50.h" | 
|  | #include "zcrypt_error.h" | 
|  | #include "zcrypt_cex4.h" | 
|  |  | 
|  | #define CEX4A_MIN_MOD_SIZE	  1	/*    8 bits	*/ | 
|  | #define CEX4A_MAX_MOD_SIZE_2K	256	/* 2048 bits	*/ | 
|  | #define CEX4A_MAX_MOD_SIZE_4K	512	/* 4096 bits	*/ | 
|  |  | 
|  | #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 | 
|  |  | 
|  | /* Waiting time for requests to be processed. | 
|  | * Currently there are some types of request which are not deterministic. | 
|  | * But the maximum time limit managed by the stomper code is set to 60sec. | 
|  | * Hence we have to wait at least that time period. | 
|  | */ | 
|  | #define CEX4_CLEANUP_TIME	(61*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_driver zcrypt_cex4_driver = { | 
|  | .probe = zcrypt_cex4_probe, | 
|  | .remove = zcrypt_cex4_remove, | 
|  | .ids = zcrypt_cex4_ids, | 
|  | .request_timeout = CEX4_CLEANUP_TIME, | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Probe function for CEX4 cards. 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) | 
|  | { | 
|  | struct zcrypt_device *zdev = NULL; | 
|  | 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"; | 
|  | zdev->speed_rating = CEX4A_SPEED_RATING; | 
|  | } else { | 
|  | zdev->type_string = "CEX5A"; | 
|  | zdev->speed_rating = CEX5A_SPEED_RATING; | 
|  | } | 
|  | 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_request(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"; | 
|  | zdev->speed_rating = CEX4C_SPEED_RATING; | 
|  | } else { | 
|  | zdev->type_string = "CEX5C"; | 
|  | zdev->speed_rating = CEX5C_SPEED_RATING; | 
|  | } | 
|  | 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_request(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"; | 
|  | zdev->speed_rating = CEX4P_SPEED_RATING; | 
|  | } else { | 
|  | zdev->type_string = "CEX5P"; | 
|  | zdev->speed_rating = CEX5P_SPEED_RATING; | 
|  | } | 
|  | 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_request(MSGTYPE06_NAME, | 
|  | MSGTYPE06_VARIANT_EP11); | 
|  | } | 
|  | break; | 
|  | } | 
|  | if (!zdev) | 
|  | return -ENODEV; | 
|  | zdev->ap_dev = ap_dev; | 
|  | zdev->online = 1; | 
|  | ap_dev->reply = &zdev->reply; | 
|  | ap_dev->private = zdev; | 
|  | rc = zcrypt_device_register(zdev); | 
|  | if (rc) { | 
|  | zcrypt_msgtype_release(zdev->ops); | 
|  | ap_dev->private = NULL; | 
|  | zcrypt_device_free(zdev); | 
|  | } | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This is called to remove the extended CEX4 driver information | 
|  | * if an AP device is removed. | 
|  | */ | 
|  | 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); | 
|  | } | 
|  | } | 
|  |  | 
|  | int __init zcrypt_cex4_init(void) | 
|  | { | 
|  | return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4"); | 
|  | } | 
|  |  | 
|  | void __exit zcrypt_cex4_exit(void) | 
|  | { | 
|  | ap_driver_unregister(&zcrypt_cex4_driver); | 
|  | } | 
|  |  | 
|  | module_init(zcrypt_cex4_init); | 
|  | module_exit(zcrypt_cex4_exit); |