18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright IBM Corp. 2001, 2012
48c2ecf20Sopenharmony_ci *  Author(s): Robert Burroughs
58c2ecf20Sopenharmony_ci *	       Eric Rossman (edrossma@us.ibm.com)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
88c2ecf20Sopenharmony_ci *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
98c2ecf20Sopenharmony_ci *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
108c2ecf20Sopenharmony_ci *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/atomic.h>
188c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
198c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "ap_bus.h"
228c2ecf20Sopenharmony_ci#include "zcrypt_api.h"
238c2ecf20Sopenharmony_ci#include "zcrypt_error.h"
248c2ecf20Sopenharmony_ci#include "zcrypt_cex2a.h"
258c2ecf20Sopenharmony_ci#include "zcrypt_msgtype50.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define CEX2A_MIN_MOD_SIZE	  1	/*    8 bits	*/
288c2ecf20Sopenharmony_ci#define CEX2A_MAX_MOD_SIZE	256	/* 2048 bits	*/
298c2ecf20Sopenharmony_ci#define CEX3A_MIN_MOD_SIZE	CEX2A_MIN_MOD_SIZE
308c2ecf20Sopenharmony_ci#define CEX3A_MAX_MOD_SIZE	512	/* 4096 bits	*/
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define CEX2A_MAX_MESSAGE_SIZE	0x390	/* sizeof(struct type50_crb2_msg)    */
338c2ecf20Sopenharmony_ci#define CEX2A_MAX_RESPONSE_SIZE 0x110	/* max outputdatalength + type80_hdr */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define CEX3A_MAX_RESPONSE_SIZE	0x210	/* 512 bit modulus
368c2ecf20Sopenharmony_ci					 * (max outputdatalength) +
378c2ecf20Sopenharmony_ci					 * type80_hdr*/
388c2ecf20Sopenharmony_ci#define CEX3A_MAX_MESSAGE_SIZE	sizeof(struct type50_crb3_msg)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define CEX2A_CLEANUP_TIME	(15*HZ)
418c2ecf20Sopenharmony_ci#define CEX3A_CLEANUP_TIME	CEX2A_CLEANUP_TIME
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ciMODULE_AUTHOR("IBM Corporation");
448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CEX2A/CEX3A Cryptographic Coprocessor device driver, " \
458c2ecf20Sopenharmony_ci		   "Copyright IBM Corp. 2001, 2018");
468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic struct ap_device_id zcrypt_cex2a_card_ids[] = {
498c2ecf20Sopenharmony_ci	{ .dev_type = AP_DEVICE_TYPE_CEX2A,
508c2ecf20Sopenharmony_ci	  .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
518c2ecf20Sopenharmony_ci	{ .dev_type = AP_DEVICE_TYPE_CEX3A,
528c2ecf20Sopenharmony_ci	  .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
538c2ecf20Sopenharmony_ci	{ /* end of list */ },
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(ap, zcrypt_cex2a_card_ids);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic struct ap_device_id zcrypt_cex2a_queue_ids[] = {
598c2ecf20Sopenharmony_ci	{ .dev_type = AP_DEVICE_TYPE_CEX2A,
608c2ecf20Sopenharmony_ci	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
618c2ecf20Sopenharmony_ci	{ .dev_type = AP_DEVICE_TYPE_CEX3A,
628c2ecf20Sopenharmony_ci	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
638c2ecf20Sopenharmony_ci	{ /* end of list */ },
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(ap, zcrypt_cex2a_queue_ids);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/**
698c2ecf20Sopenharmony_ci * Probe function for CEX2A card devices. It always accepts the AP device
708c2ecf20Sopenharmony_ci * since the bus_match already checked the card type.
718c2ecf20Sopenharmony_ci * @ap_dev: pointer to the AP device.
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistatic int zcrypt_cex2a_card_probe(struct ap_device *ap_dev)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	/*
768c2ecf20Sopenharmony_ci	 * Normalized speed ratings per crypto adapter
778c2ecf20Sopenharmony_ci	 * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci	static const int CEX2A_SPEED_IDX[] = {
808c2ecf20Sopenharmony_ci		800, 1000, 2000,  900, 1200, 2400, 0, 0};
818c2ecf20Sopenharmony_ci	static const int CEX3A_SPEED_IDX[] = {
828c2ecf20Sopenharmony_ci		400,  500, 1000,  450,	550, 1200, 0, 0};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	struct ap_card *ac = to_ap_card(&ap_dev->device);
858c2ecf20Sopenharmony_ci	struct zcrypt_card *zc;
868c2ecf20Sopenharmony_ci	int rc = 0;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	zc = zcrypt_card_alloc();
898c2ecf20Sopenharmony_ci	if (!zc)
908c2ecf20Sopenharmony_ci		return -ENOMEM;
918c2ecf20Sopenharmony_ci	zc->card = ac;
928c2ecf20Sopenharmony_ci	ac->private = zc;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) {
958c2ecf20Sopenharmony_ci		zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
968c2ecf20Sopenharmony_ci		zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
978c2ecf20Sopenharmony_ci		zc->speed_rating = CEX2A_SPEED_IDX;
988c2ecf20Sopenharmony_ci		zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
998c2ecf20Sopenharmony_ci		zc->type_string = "CEX2A";
1008c2ecf20Sopenharmony_ci		zc->user_space_type = ZCRYPT_CEX2A;
1018c2ecf20Sopenharmony_ci	} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX3A) {
1028c2ecf20Sopenharmony_ci		zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
1038c2ecf20Sopenharmony_ci		zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
1048c2ecf20Sopenharmony_ci		zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
1058c2ecf20Sopenharmony_ci		if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
1068c2ecf20Sopenharmony_ci		    ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) {
1078c2ecf20Sopenharmony_ci			zc->max_mod_size = CEX3A_MAX_MOD_SIZE;
1088c2ecf20Sopenharmony_ci			zc->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci		zc->speed_rating = CEX3A_SPEED_IDX;
1118c2ecf20Sopenharmony_ci		zc->type_string = "CEX3A";
1128c2ecf20Sopenharmony_ci		zc->user_space_type = ZCRYPT_CEX3A;
1138c2ecf20Sopenharmony_ci	} else {
1148c2ecf20Sopenharmony_ci		zcrypt_card_free(zc);
1158c2ecf20Sopenharmony_ci		return -ENODEV;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci	zc->online = 1;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	rc = zcrypt_card_register(zc);
1208c2ecf20Sopenharmony_ci	if (rc) {
1218c2ecf20Sopenharmony_ci		ac->private = NULL;
1228c2ecf20Sopenharmony_ci		zcrypt_card_free(zc);
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	return rc;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/**
1298c2ecf20Sopenharmony_ci * This is called to remove the CEX2A card driver information
1308c2ecf20Sopenharmony_ci * if an AP card device is removed.
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_cistatic void zcrypt_cex2a_card_remove(struct ap_device *ap_dev)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (zc)
1378c2ecf20Sopenharmony_ci		zcrypt_card_unregister(zc);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic struct ap_driver zcrypt_cex2a_card_driver = {
1418c2ecf20Sopenharmony_ci	.probe = zcrypt_cex2a_card_probe,
1428c2ecf20Sopenharmony_ci	.remove = zcrypt_cex2a_card_remove,
1438c2ecf20Sopenharmony_ci	.ids = zcrypt_cex2a_card_ids,
1448c2ecf20Sopenharmony_ci	.flags = AP_DRIVER_FLAG_DEFAULT,
1458c2ecf20Sopenharmony_ci};
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/**
1488c2ecf20Sopenharmony_ci * Probe function for CEX2A queue devices. It always accepts the AP device
1498c2ecf20Sopenharmony_ci * since the bus_match already checked the queue type.
1508c2ecf20Sopenharmony_ci * @ap_dev: pointer to the AP device.
1518c2ecf20Sopenharmony_ci */
1528c2ecf20Sopenharmony_cistatic int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct ap_queue *aq = to_ap_queue(&ap_dev->device);
1558c2ecf20Sopenharmony_ci	struct zcrypt_queue *zq = NULL;
1568c2ecf20Sopenharmony_ci	int rc;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	switch (ap_dev->device_type) {
1598c2ecf20Sopenharmony_ci	case AP_DEVICE_TYPE_CEX2A:
1608c2ecf20Sopenharmony_ci		zq = zcrypt_queue_alloc(CEX2A_MAX_RESPONSE_SIZE);
1618c2ecf20Sopenharmony_ci		if (!zq)
1628c2ecf20Sopenharmony_ci			return -ENOMEM;
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	case AP_DEVICE_TYPE_CEX3A:
1658c2ecf20Sopenharmony_ci		zq = zcrypt_queue_alloc(CEX3A_MAX_RESPONSE_SIZE);
1668c2ecf20Sopenharmony_ci		if (!zq)
1678c2ecf20Sopenharmony_ci			return -ENOMEM;
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci	if (!zq)
1718c2ecf20Sopenharmony_ci		return -ENODEV;
1728c2ecf20Sopenharmony_ci	zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
1738c2ecf20Sopenharmony_ci	zq->queue = aq;
1748c2ecf20Sopenharmony_ci	zq->online = 1;
1758c2ecf20Sopenharmony_ci	atomic_set(&zq->load, 0);
1768c2ecf20Sopenharmony_ci	ap_queue_init_state(aq);
1778c2ecf20Sopenharmony_ci	ap_queue_init_reply(aq, &zq->reply);
1788c2ecf20Sopenharmony_ci	aq->request_timeout = CEX2A_CLEANUP_TIME,
1798c2ecf20Sopenharmony_ci	aq->private = zq;
1808c2ecf20Sopenharmony_ci	rc = zcrypt_queue_register(zq);
1818c2ecf20Sopenharmony_ci	if (rc) {
1828c2ecf20Sopenharmony_ci		aq->private = NULL;
1838c2ecf20Sopenharmony_ci		zcrypt_queue_free(zq);
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return rc;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/**
1908c2ecf20Sopenharmony_ci * This is called to remove the CEX2A queue driver information
1918c2ecf20Sopenharmony_ci * if an AP queue device is removed.
1928c2ecf20Sopenharmony_ci */
1938c2ecf20Sopenharmony_cistatic void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct ap_queue *aq = to_ap_queue(&ap_dev->device);
1968c2ecf20Sopenharmony_ci	struct zcrypt_queue *zq = aq->private;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (zq)
1998c2ecf20Sopenharmony_ci		zcrypt_queue_unregister(zq);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic struct ap_driver zcrypt_cex2a_queue_driver = {
2038c2ecf20Sopenharmony_ci	.probe = zcrypt_cex2a_queue_probe,
2048c2ecf20Sopenharmony_ci	.remove = zcrypt_cex2a_queue_remove,
2058c2ecf20Sopenharmony_ci	.ids = zcrypt_cex2a_queue_ids,
2068c2ecf20Sopenharmony_ci	.flags = AP_DRIVER_FLAG_DEFAULT,
2078c2ecf20Sopenharmony_ci};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ciint __init zcrypt_cex2a_init(void)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	int rc;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	rc = ap_driver_register(&zcrypt_cex2a_card_driver,
2148c2ecf20Sopenharmony_ci				THIS_MODULE, "cex2acard");
2158c2ecf20Sopenharmony_ci	if (rc)
2168c2ecf20Sopenharmony_ci		return rc;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	rc = ap_driver_register(&zcrypt_cex2a_queue_driver,
2198c2ecf20Sopenharmony_ci				THIS_MODULE, "cex2aqueue");
2208c2ecf20Sopenharmony_ci	if (rc)
2218c2ecf20Sopenharmony_ci		ap_driver_unregister(&zcrypt_cex2a_card_driver);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	return rc;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_civoid __exit zcrypt_cex2a_exit(void)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	ap_driver_unregister(&zcrypt_cex2a_queue_driver);
2298c2ecf20Sopenharmony_ci	ap_driver_unregister(&zcrypt_cex2a_card_driver);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cimodule_init(zcrypt_cex2a_init);
2338c2ecf20Sopenharmony_cimodule_exit(zcrypt_cex2a_exit);
234