diff options
Diffstat (limited to 'drivers/s390/crypto/zcrypt_cex4.c')
| -rw-r--r-- | drivers/s390/crypto/zcrypt_cex4.c | 167 | 
1 files changed, 167 insertions, 0 deletions
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c new file mode 100644 index 00000000000..569f8b1d86c --- /dev/null +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -0,0 +1,167 @@ +/* + *  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 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)  }, +	{ /* 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: +		if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) { +			zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE); +			if (!zdev) +				return -ENOMEM; +			zdev->type_string = "CEX4A"; +			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->speed_rating = CEX4A_SPEED_RATING; +			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; +			zdev->type_string = "CEX4C"; +			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->speed_rating = CEX4C_SPEED_RATING; +			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; +			zdev->type_string = "CEX4P"; +			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->speed_rating = CEX4C_SPEED_RATING; +			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);  | 
