aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto')
-rw-r--r--drivers/s390/crypto/zcrypt_api.c308
-rw-r--r--drivers/s390/crypto/zcrypt_api.h26
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c12
-rw-r--r--drivers/s390/crypto/zcrypt_cex4.c36
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.c32
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.h3
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c403
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.h17
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c41
9 files changed, 629 insertions, 249 deletions
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index dc6d891a7b48..28913e540096 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -151,18 +151,16 @@ static inline int zcrypt_process_rescan(void)
* Need to be called while holding the zcrypt device list lock.
* Note: cards with speed_rating of 0 are kept at the end of the list.
*/
-static void __zcrypt_increase_preference(struct zcrypt_device *zdev)
+static void __zcrypt_increase_preference(struct zcrypt_device *zdev,
+ unsigned int weight)
{
struct zcrypt_device *tmp;
struct list_head *l;
- if (zdev->speed_rating == 0)
- return;
+ zdev->load -= weight;
for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) {
tmp = list_entry(l, struct zcrypt_device, list);
- if ((tmp->request_count + 1) * tmp->speed_rating <=
- (zdev->request_count + 1) * zdev->speed_rating &&
- tmp->speed_rating != 0)
+ if (tmp->load <= zdev->load)
break;
}
if (l == zdev->list.prev)
@@ -179,18 +177,16 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev)
* Need to be called while holding the zcrypt device list lock.
* Note: cards with speed_rating of 0 are kept at the end of the list.
*/
-static void __zcrypt_decrease_preference(struct zcrypt_device *zdev)
+static void __zcrypt_decrease_preference(struct zcrypt_device *zdev,
+ unsigned int weight)
{
struct zcrypt_device *tmp;
struct list_head *l;
- if (zdev->speed_rating == 0)
- return;
+ zdev->load += weight;
for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) {
tmp = list_entry(l, struct zcrypt_device, list);
- if ((tmp->request_count + 1) * tmp->speed_rating >
- (zdev->request_count + 1) * zdev->speed_rating ||
- tmp->speed_rating == 0)
+ if (tmp->load > zdev->load)
break;
}
if (l == zdev->list.next)
@@ -270,7 +266,7 @@ int zcrypt_device_register(struct zcrypt_device *zdev)
ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid,
zdev->online);
list_add_tail(&zdev->list, &zcrypt_device_list);
- __zcrypt_increase_preference(zdev);
+ __zcrypt_increase_preference(zdev, 0); /* sort devices acc. weight */
zcrypt_device_count++;
spin_unlock_bh(&zcrypt_device_lock);
if (zdev->ops->rng) {
@@ -386,8 +382,9 @@ static int zcrypt_release(struct inode *inode, struct file *filp)
*/
static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
{
- struct zcrypt_device *zdev;
+ struct zcrypt_device *zdev, *pref_zdev = NULL;
int rc;
+ unsigned int weight, func_code, pref_weight = 0;
if (mex->outputdatalength < mex->inputdatalength)
return -EINVAL;
@@ -398,6 +395,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
*/
mex->outputdatalength = mex->inputdatalength;
+ rc = get_rsa_modex_fc(mex, &func_code);
+ if (rc)
+ return rc;
+
spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) {
if (!zdev->online ||
@@ -405,34 +406,52 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
zdev->min_mod_size > mex->inputdatalength ||
zdev->max_mod_size < mex->inputdatalength)
continue;
- zcrypt_device_get(zdev);
- get_device(&zdev->ap_dev->device);
- zdev->request_count++;
- __zcrypt_decrease_preference(zdev);
- if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
- spin_unlock_bh(&zcrypt_device_lock);
- rc = zdev->ops->rsa_modexpo(zdev, mex);
- spin_lock_bh(&zcrypt_device_lock);
- module_put(zdev->ap_dev->drv->driver.owner);
+ weight = zdev->speed_rating[func_code];
+ if (!pref_zdev) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
}
- else
- rc = -EAGAIN;
- zdev->request_count--;
- __zcrypt_increase_preference(zdev);
- put_device(&zdev->ap_dev->device);
- zcrypt_device_put(zdev);
+ if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
+ }
+ if ((pref_zdev->load + pref_weight) <= zdev->load)
+ break; /* Load on remaining devices too high - abort */
+ }
+
+ if (!pref_zdev) {
spin_unlock_bh(&zcrypt_device_lock);
- return rc;
+ return -ENODEV;
}
+ __zcrypt_decrease_preference(pref_zdev, pref_weight);
+ zcrypt_device_get(pref_zdev);
+ get_device(&pref_zdev->ap_dev->device);
+ pref_zdev->request_count++;
+ if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
+ spin_unlock_bh(&zcrypt_device_lock);
+ rc = -ENODEV;
+ rc = pref_zdev->ops->rsa_modexpo(pref_zdev, mex);
+ spin_lock_bh(&zcrypt_device_lock);
+ module_put(pref_zdev->ap_dev->drv->driver.owner);
+ } else
+ rc = -EAGAIN;
+
+ pref_zdev->request_count--;
+ __zcrypt_increase_preference(pref_zdev, pref_weight);
+ put_device(&pref_zdev->ap_dev->device);
+ zcrypt_device_put(pref_zdev);
spin_unlock_bh(&zcrypt_device_lock);
- return -ENODEV;
+ return rc;
}
static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
{
- struct zcrypt_device *zdev;
+ struct zcrypt_device *zdev, *pref_zdev = NULL;
unsigned long long z1, z2, z3;
int rc, copied;
+ unsigned int weight, func_code, pref_weight = 0;
if (crt->outputdatalength < crt->inputdatalength)
return -EINVAL;
@@ -443,6 +462,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
*/
crt->outputdatalength = crt->inputdatalength;
+ rc = get_rsa_crt_fc(crt, &func_code);
+ if (rc)
+ return rc;
+
copied = 0;
restart:
spin_lock_bh(&zcrypt_device_lock);
@@ -489,33 +512,54 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
/* The device can't handle this request. */
continue;
}
- zcrypt_device_get(zdev);
- get_device(&zdev->ap_dev->device);
- zdev->request_count++;
- __zcrypt_decrease_preference(zdev);
- if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
- spin_unlock_bh(&zcrypt_device_lock);
- rc = zdev->ops->rsa_modexpo_crt(zdev, crt);
- spin_lock_bh(&zcrypt_device_lock);
- module_put(zdev->ap_dev->drv->driver.owner);
+
+ weight = zdev->speed_rating[func_code];
+ if (!pref_zdev) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
+ }
+ if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
}
- else
- rc = -EAGAIN;
- zdev->request_count--;
- __zcrypt_increase_preference(zdev);
- put_device(&zdev->ap_dev->device);
- zcrypt_device_put(zdev);
+ if ((pref_zdev->load + pref_weight) <= zdev->load)
+ break; /* Load on remaining devices too high - abort */
+ }
+ if (!pref_zdev) {
spin_unlock_bh(&zcrypt_device_lock);
- return rc;
+ return -ENODEV;
}
+ __zcrypt_decrease_preference(pref_zdev, pref_weight);
+ zcrypt_device_get(pref_zdev);
+ get_device(&pref_zdev->ap_dev->device);
+ pref_zdev->request_count++;
+ if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
+ spin_unlock_bh(&zcrypt_device_lock);
+ rc = pref_zdev->ops->rsa_modexpo_crt(pref_zdev, crt);
+ spin_lock_bh(&zcrypt_device_lock);
+ module_put(pref_zdev->ap_dev->drv->driver.owner);
+ } else
+ rc = -EAGAIN;
+ pref_zdev->request_count--;
+ __zcrypt_increase_preference(pref_zdev, pref_weight);
+ put_device(&pref_zdev->ap_dev->device);
+ zcrypt_device_put(pref_zdev);
spin_unlock_bh(&zcrypt_device_lock);
- return -ENODEV;
+ return rc;
}
static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
{
- struct zcrypt_device *zdev;
+ struct zcrypt_device *zdev, *pref_zdev = NULL;
+ unsigned int weight = 0, func_code = 0, pref_weight = 0;
int rc;
+ struct ap_message ap_msg;
+
+ rc = get_cprb_fc(xcRB, &ap_msg, &func_code);
+ if (rc)
+ return rc;
spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) {
@@ -524,27 +568,42 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
(xcRB->user_defined != AUTOSELECT &&
AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined))
continue;
- zcrypt_device_get(zdev);
- get_device(&zdev->ap_dev->device);
- zdev->request_count++;
- __zcrypt_decrease_preference(zdev);
- if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
- spin_unlock_bh(&zcrypt_device_lock);
- rc = zdev->ops->send_cprb(zdev, xcRB);
- spin_lock_bh(&zcrypt_device_lock);
- module_put(zdev->ap_dev->drv->driver.owner);
+
+ weight = speed_idx_cca(func_code) * zdev->speed_rating[SECKEY];
+ if (!pref_zdev) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
+ }
+ if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
}
- else
- rc = -EAGAIN;
- zdev->request_count--;
- __zcrypt_increase_preference(zdev);
- put_device(&zdev->ap_dev->device);
- zcrypt_device_put(zdev);
+ if ((pref_zdev->load + pref_weight) <= zdev->load)
+ break; /* Load on remaining devices too high - abort */
+ }
+ if (!pref_zdev) {
spin_unlock_bh(&zcrypt_device_lock);
- return rc;
+ return -ENODEV;
}
+ __zcrypt_decrease_preference(pref_zdev, pref_weight);
+ zcrypt_device_get(pref_zdev);
+ get_device(&pref_zdev->ap_dev->device);
+ pref_zdev->request_count++;
+ if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
+ spin_unlock_bh(&zcrypt_device_lock);
+ rc = pref_zdev->ops->send_cprb(pref_zdev, xcRB, &ap_msg);
+ spin_lock_bh(&zcrypt_device_lock);
+ module_put(pref_zdev->ap_dev->drv->driver.owner);
+ } else
+ rc = -EAGAIN;
+ pref_zdev->request_count--;
+ __zcrypt_increase_preference(pref_zdev, pref_weight);
+ put_device(&pref_zdev->ap_dev->device);
+ zcrypt_device_put(pref_zdev);
spin_unlock_bh(&zcrypt_device_lock);
- return -ENODEV;
+ return rc;
}
struct ep11_target_dev_list {
@@ -568,7 +627,9 @@ static bool is_desired_ep11dev(unsigned int dev_qid,
static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
{
- struct zcrypt_device *zdev;
+ struct zcrypt_device *zdev, *pref_zdev = NULL;
+ struct ap_message ap_msg;
+ unsigned int weight = 0, func_code = 0, pref_weight = 0;
bool autoselect = false;
int rc;
struct ep11_target_dev_list ep11_dev_list = {
@@ -596,6 +657,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
return -EFAULT;
}
+ rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code);
+ if (rc)
+ return rc;
+
spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) {
/* check if device is eligible */
@@ -608,58 +673,93 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
!autoselect)
continue;
- zcrypt_device_get(zdev);
- get_device(&zdev->ap_dev->device);
- zdev->request_count++;
- __zcrypt_decrease_preference(zdev);
- if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
- spin_unlock_bh(&zcrypt_device_lock);
- rc = zdev->ops->send_ep11_cprb(zdev, xcrb);
- spin_lock_bh(&zcrypt_device_lock);
- module_put(zdev->ap_dev->drv->driver.owner);
- } else {
- rc = -EAGAIN;
- }
- zdev->request_count--;
- __zcrypt_increase_preference(zdev);
- put_device(&zdev->ap_dev->device);
- zcrypt_device_put(zdev);
+ weight = speed_idx_ep11(func_code) * zdev->speed_rating[SECKEY];
+ if (!pref_zdev) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
+ }
+ if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
+ }
+ if ((pref_zdev->load + pref_weight) <= zdev->load)
+ break; /* Load on remaining devices too high - abort */
+ }
+ if (!pref_zdev) {
spin_unlock_bh(&zcrypt_device_lock);
- return rc;
+ return -ENODEV;
+ }
+
+ zcrypt_device_get(pref_zdev);
+ get_device(&pref_zdev->ap_dev->device);
+ pref_zdev->request_count++;
+ if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
+ spin_unlock_bh(&zcrypt_device_lock);
+ rc = pref_zdev->ops->send_ep11_cprb(pref_zdev, xcrb, &ap_msg);
+ spin_lock_bh(&zcrypt_device_lock);
+ module_put(pref_zdev->ap_dev->drv->driver.owner);
+ } else {
+ rc = -EAGAIN;
}
+ pref_zdev->request_count--;
+ put_device(&pref_zdev->ap_dev->device);
+ zcrypt_device_put(pref_zdev);
spin_unlock_bh(&zcrypt_device_lock);
- return -ENODEV;
+ return rc;
}
static long zcrypt_rng(char *buffer)
{
- struct zcrypt_device *zdev;
+ struct zcrypt_device *zdev, *pref_zdev = NULL;
+ struct ap_message ap_msg;
+ unsigned int weight = 0, func_code = 0, pref_weight = 0;
int rc;
+ rc = get_rng_fc(&ap_msg, &func_code);
+ if (rc)
+ return rc;
+
spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) {
if (!zdev->online || !zdev->ops->rng)
continue;
- zcrypt_device_get(zdev);
- get_device(&zdev->ap_dev->device);
- zdev->request_count++;
- __zcrypt_decrease_preference(zdev);
- if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
- spin_unlock_bh(&zcrypt_device_lock);
- rc = zdev->ops->rng(zdev, buffer);
- spin_lock_bh(&zcrypt_device_lock);
- module_put(zdev->ap_dev->drv->driver.owner);
- } else
- rc = -EAGAIN;
- zdev->request_count--;
- __zcrypt_increase_preference(zdev);
- put_device(&zdev->ap_dev->device);
- zcrypt_device_put(zdev);
+
+ weight = zdev->speed_rating[func_code];
+ if (!pref_zdev) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
+ }
+ if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
+ pref_zdev = zdev;
+ pref_weight = weight;
+ continue;
+ }
+ if ((pref_zdev->load + pref_weight) <= zdev->load)
+ break; /* Load on remaining devices too high - abort */
+ }
+ if (!pref_zdev) {
spin_unlock_bh(&zcrypt_device_lock);
- return rc;
+ return -ENODEV;
}
+
+ zcrypt_device_get(pref_zdev);
+ get_device(&pref_zdev->ap_dev->device);
+ pref_zdev->request_count++;
+ if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
+ spin_unlock_bh(&zcrypt_device_lock);
+ rc = pref_zdev->ops->rng(pref_zdev, buffer, &ap_msg);
+ spin_lock_bh(&zcrypt_device_lock);
+ module_put(pref_zdev->ap_dev->drv->driver.owner);
+ } else
+ rc = -EAGAIN;
+ pref_zdev->request_count--;
+ put_device(&pref_zdev->ap_dev->device);
+ zcrypt_device_put(pref_zdev);
spin_unlock_bh(&zcrypt_device_lock);
- return -ENODEV;
+ return rc;
}
static void zcrypt_status_mask(char status[AP_DEVICES])
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 326ecdc0417f..3d0d1e25d751 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -84,15 +84,32 @@ struct ica_z90_status {
*/
#define ZCRYPT_RNG_BUFFER_SIZE 4096
+/*
+ * Identifier for Crypto Request Performance Index
+ */
+enum crypto_ops {
+ MEX_1K = 0,
+ MEX_2K,
+ MEX_4K,
+ CRT_1K,
+ CRT_2K,
+ CRT_4K,
+ HWRNG,
+ SECKEY,
+ NUM_OPS
+};
+
struct zcrypt_device;
struct zcrypt_ops {
long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
long (*rsa_modexpo_crt)(struct zcrypt_device *,
struct ica_rsa_modexpo_crt *);
- long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *);
- long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *);
- long (*rng)(struct zcrypt_device *, char *);
+ long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *,
+ struct ap_message *);
+ long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *,
+ struct ap_message *);
+ long (*rng)(struct zcrypt_device *, char *, struct ap_message *);
struct list_head list; /* zcrypt ops list. */
struct module *owner;
int variant;
@@ -112,7 +129,8 @@ struct zcrypt_device {
int min_mod_size; /* Min number of bits. */
int max_mod_size; /* Max number of bits. */
int short_crt; /* Card has crt length restriction. */
- int speed_rating; /* Speed of the crypto device. */
+ int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */
+ int load; /* Utilization of the crypto device */
int request_count; /* # current requests. */
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index d892cb539139..4bb13eadd0f1 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -43,9 +43,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 */
@@ -87,6 +84,8 @@ static struct ap_driver zcrypt_cex2a_driver = {
static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev = NULL;
+ int CEX2A_SPEED_IDX[] = { 800, 1000, 2000, 900, 1200, 2400, 0};
+ int CEX3A_SPEED_IDX[] = { 400, 500, 1000, 450, 550, 1200, 0};
int rc = 0;
switch (ap_dev->device_type) {
@@ -99,7 +98,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
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;
+ memcpy(zdev->speed_rating, CEX2A_SPEED_IDX,
+ sizeof(CEX2A_SPEED_IDX));
zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
break;
case AP_DEVICE_TYPE_CEX3A:
@@ -117,7 +117,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
}
zdev->short_crt = 1;
- zdev->speed_rating = CEX3A_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX3A_SPEED_IDX,
+ sizeof(CEX3A_SPEED_IDX));
break;
}
if (!zdev)
@@ -125,6 +126,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
zdev->ap_dev = ap_dev;
zdev->online = 1;
+ zdev->load = zdev->speed_rating[0];
ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index e98bdbe45d2c..ff28ad543c30 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -24,13 +24,6 @@
#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
@@ -71,6 +64,16 @@ static struct ap_driver zcrypt_cex4_driver = {
static int zcrypt_cex4_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
+ */
+ int CEX4A_SPEED_IDX[] = { 5, 6, 59, 20, 115, 581, 0, 0};
+ int CEX5A_SPEED_IDX[] = { 3, 3, 6, 8, 32, 218, 0, 0};
+ int CEX4C_SPEED_IDX[] = { 24, 25, 82, 41, 138, 1111, 79, 8};
+ int CEX5C_SPEED_IDX[] = { 10, 14, 23, 17, 45, 242, 63, 4};
+ int CEX4P_SPEED_IDX[] = {142, 198, 1852, 203, 331, 1563, 0, 8};
+ int CEX5P_SPEED_IDX[] = { 49, 67, 131, 52, 85, 287, 0, 4};
int rc = 0;
switch (ap_dev->device_type) {
@@ -82,10 +85,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4A";
- zdev->speed_rating = CEX4A_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX4A_SPEED_IDX,
+ sizeof(CEX4A_SPEED_IDX));
} else {
zdev->type_string = "CEX5A";
- zdev->speed_rating = CEX5A_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX5A_SPEED_IDX,
+ sizeof(CEX5A_SPEED_IDX));
}
zdev->user_space_type = ZCRYPT_CEX3A;
zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
@@ -110,10 +115,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4C";
- zdev->speed_rating = CEX4C_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX4C_SPEED_IDX,
+ sizeof(CEX4C_SPEED_IDX));
} else {
zdev->type_string = "CEX5C";
- zdev->speed_rating = CEX5C_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX5C_SPEED_IDX,
+ sizeof(CEX5C_SPEED_IDX));
}
zdev->user_space_type = ZCRYPT_CEX3C;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
@@ -128,10 +135,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4P";
- zdev->speed_rating = CEX4P_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX4P_SPEED_IDX,
+ sizeof(CEX4P_SPEED_IDX));
} else {
zdev->type_string = "CEX5P";
- zdev->speed_rating = CEX5P_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX5P_SPEED_IDX,
+ sizeof(CEX5P_SPEED_IDX));
}
zdev->user_space_type = ZCRYPT_CEX4;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
@@ -147,6 +156,7 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENODEV;
zdev->ap_dev = ap_dev;
zdev->online = 1;
+ zdev->load = zdev->speed_rating[0];
ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
index 7bafba83390a..fb97479af3f8 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.c
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -173,6 +173,38 @@ struct type80_hdr {
unsigned char reserved3[8];
} __packed;
+unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *mex, int *fcode)
+{
+
+ if (!mex->inputdatalength)
+ return -EINVAL;
+
+ if (mex->inputdatalength <= 128) /* 1024 bit */
+ *fcode = MEX_1K;
+ else if (mex->inputdatalength <= 256) /* 2048 bit */
+ *fcode = MEX_2K;
+ else /* 4096 bit */
+ *fcode = MEX_4K;
+
+ return 0;
+}
+
+unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode)
+{
+
+ if (!crt->inputdatalength)
+ return -EINVAL;
+
+ if (crt->inputdatalength <= 128) /* 1024 bit */
+ *fcode = CRT_1K;
+ else if (crt->inputdatalength <= 256) /* 2048 bit */
+ *fcode = CRT_2K;
+ else /* 4096 bit */
+ *fcode = CRT_4K;
+
+ return 0;
+}
+
/**
* Convert a ICAMEX message to a type50 MEX message.
*
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h
index eeb41c0f34ae..5cc280318ee7 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.h
+++ b/drivers/s390/crypto/zcrypt_msgtype50.h
@@ -35,6 +35,9 @@
#define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/
+unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *, int *);
+unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *, int *);
+
void zcrypt_msgtype50_init(void);
void zcrypt_msgtype50_exit(void);
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index f71949685ff5..957a88d5768b 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -149,6 +149,112 @@ static struct CPRBX static_cprbx = {
.func_id = {0x54, 0x32},
};
+int speed_idx_cca(int req_type)
+{
+ switch (req_type) {
+ case 0x4142:
+ case 0x4149:
+ case 0x414D:
+ case 0x4341:
+ case 0x4344:
+ case 0x4354:
+ case 0x4358:
+ case 0x444B:
+ case 0x4558:
+ case 0x4643:
+ case 0x4651:
+ case 0x4C47:
+ case 0x4C4B:
+ case 0x4C51:
+ case 0x4F48:
+ case 0x504F:
+ case 0x5053:
+ case 0x5058:
+ case 0x5343:
+ case 0x5344:
+ case 0x5345:
+ case 0x5350:
+ return LOW;
+ case 0x414B:
+ case 0x4345:
+ case 0x4349:
+ case 0x434D:
+ case 0x4847:
+ case 0x4849:
+ case 0x484D:
+ case 0x4850:
+ case 0x4851:
+ case 0x4954:
+ case 0x4958:
+ case 0x4B43:
+ case 0x4B44:
+ case 0x4B45:
+ case 0x4B47:
+ case 0x4B48:
+ case 0x4B49:
+ case 0x4B4E:
+ case 0x4B50:
+ case 0x4B52:
+ case 0x4B54:
+ case 0x4B58:
+ case 0x4D50:
+ case 0x4D53:
+ case 0x4D56:
+ case 0x4D58:
+ case 0x5044:
+ case 0x5045:
+ case 0x5046:
+ case 0x5047:
+ case 0x5049:
+ case 0x504B:
+ case 0x504D:
+ case 0x5254:
+ case 0x5347:
+ case 0x5349:
+ case 0x534B:
+ case 0x534D:
+ case 0x5356:
+ case 0x5358:
+ case 0x5443:
+ case 0x544B:
+ case 0x5647:
+ return HIGH;
+ default:
+ return MEDIUM;
+ }
+}
+
+int speed_idx_ep11(int req_type)
+{
+ switch (req_type) {
+ case 1:
+ case 2:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ return LOW;
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 26:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ return HIGH;
+ default:
+ return MEDIUM;
+ }
+}
+
+
/**
* Convert a ICAMEX message to a type6 MEX message.
*
@@ -297,9 +403,9 @@ struct type86_fmt2_msg {
struct type86_fmt2_ext fmt2;
} __packed;
-static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
- struct ap_message *ap_msg,
- struct ica_xcRB *xcRB)
+static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
+ struct ica_xcRB *xcRB,
+ unsigned int *fcode)
{
static struct type6_hdr static_type6_hdrX = {
.type = 0x06,
@@ -379,6 +485,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
memcpy(msg->hdr.function_code, function_code,
sizeof(msg->hdr.function_code));
+ *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1];
+
if (memcmp(function_code, "US", 2) == 0)
ap_msg->special = 1;
else
@@ -392,12 +500,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
return 0;
}
-static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
- struct ap_message *ap_msg,
- struct ep11_urb *xcRB)
+static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
+ struct ep11_urb *xcRB,
+ unsigned int *fcode)
{
- unsigned int lfmt;
-
static struct type6_hdr static_type6_ep11_hdr = {
.type = 0x06,
.rqid = {0x00, 0x01},
@@ -421,7 +527,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
unsigned char dom_tag; /* fixed value 0x4 */
unsigned char dom_len; /* fixed value 0x4 */
unsigned int dom_val; /* domain id */
- } __packed * payload_hdr;
+ } __packed * payload_hdr = NULL;
if (CEIL4(xcRB->req_len) < xcRB->req_len)
return -EINVAL; /* overflow after alignment*/
@@ -450,36 +556,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
return -EFAULT;
}
- /*
- The target domain field within the cprb body/payload block will be
- replaced by the usage domain for non-management commands only.
- Therefore we check the first bit of the 'flags' parameter for
- management command indication.
- 0 - non management command
- 1 - management command
- */
- if (!((msg->cprbx.flags & 0x80) == 0x80)) {
- msg->cprbx.target_id = (unsigned int)
- AP_QID_QUEUE(zdev->ap_dev->qid);
-
- if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
- switch (msg->pld_lenfmt & 0x03) {
- case 1:
- lfmt = 2;
- break;
- case 2:
- lfmt = 3;
- break;
- default:
- return -EINVAL;
- }
- } else {
- lfmt = 1; /* length format #1 */
- }
- payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
- payload_hdr->dom_val = (unsigned int)
- AP_QID_QUEUE(zdev->ap_dev->qid);
- }
+ *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF);
return 0;
}
@@ -989,6 +1066,36 @@ out_free:
return rc;
}
+unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
+ struct ap_message *ap_msg,
+ int *func_code)
+{
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_XCRB,
+ };
+ int rc;
+
+ ap_init_message(ap_msg);
+ ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ if (!ap_msg->message)
+ return -ENOMEM;
+ ap_msg->receive = zcrypt_msgtype6_receive;
+ ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
+ if (!ap_msg->private) {
+ kzfree(ap_msg->message);
+ return -ENOMEM;
+ }
+ memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
+ rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code);
+ if (rc) {
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
+ }
+ return rc;
+}
+
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to handle a send_cprb request.
@@ -997,37 +1104,55 @@ out_free:
* @xcRB: pointer to the send_cprb request buffer
*/
static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
- struct ica_xcRB *xcRB)
+ struct ica_xcRB *xcRB,
+ struct ap_message *ap_msg)
{
- struct ap_message ap_msg;
- struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_XCRB,
- };
int rc;
+ struct response_type *rtype = (struct response_type *)(ap_msg->private);
- ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
- if (!ap_msg.message)
- return -ENOMEM;
- ap_msg.receive = zcrypt_msgtype6_receive;
- ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
- atomic_inc_return(&zcrypt_step);
- ap_msg.private = &resp_type;
- rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
- if (rc)
- goto out_free;
- init_completion(&resp_type.work);
- ap_queue_message(zdev->ap_dev, &ap_msg);
- rc = wait_for_completion_interruptible(&resp_type.work);
+ init_completion(&rtype->work);
+ ap_queue_message(zdev->ap_dev, ap_msg);
+ rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
- rc = ap_msg.rc;
+ rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
+ rc = convert_response_xcrb(zdev, ap_msg, xcRB);
} else
/* Signal pending. */
- ap_cancel_message(zdev->ap_dev, &ap_msg);
-out_free:
- kzfree(ap_msg.message);
+ ap_cancel_message(zdev->ap_dev, ap_msg);
+
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
+ return rc;
+}
+
+unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
+ struct ap_message *ap_msg,
+ int *func_code)
+{
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_EP11,
+ };
+ int rc;
+
+ ap_init_message(ap_msg);
+ ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ if (!ap_msg->message)
+ return -ENOMEM;
+ ap_msg->receive = zcrypt_msgtype6_receive_ep11;
+ ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
+ if (!ap_msg->private) {
+ kzfree(ap_msg->message);
+ return -ENOMEM;
+ }
+ memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
+ rc = xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code);
+ if (rc) {
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
+ }
return rc;
}
@@ -1039,41 +1164,101 @@ out_free:
* @xcRB: pointer to the ep11 user request block
*/
static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
- struct ep11_urb *xcrb)
+ struct ep11_urb *xcrb,
+ struct ap_message *ap_msg)
{
- struct ap_message ap_msg;
- struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_EP11,
- };
int rc;
+ unsigned int lfmt;
+ struct response_type *rtype = (struct response_type *)(ap_msg->private);
+ struct {
+ struct type6_hdr hdr;
+ struct ep11_cprb cprbx;
+ unsigned char pld_tag; /* fixed value 0x30 */
+ unsigned char pld_lenfmt; /* payload length format */
+ } __packed * msg = ap_msg->message;
+ struct pld_hdr {
+ unsigned char func_tag; /* fixed value 0x4 */
+ unsigned char func_len; /* fixed value 0x4 */
+ unsigned int func_val; /* function ID */
+ unsigned char dom_tag; /* fixed value 0x4 */
+ unsigned char dom_len; /* fixed value 0x4 */
+ unsigned int dom_val; /* domain id */
+ } __packed * payload_hdr = NULL;
- ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
- if (!ap_msg.message)
- return -ENOMEM;
- ap_msg.receive = zcrypt_msgtype6_receive_ep11;
- ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
- atomic_inc_return(&zcrypt_step);
- ap_msg.private = &resp_type;
- rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb);
- if (rc)
- goto out_free;
- init_completion(&resp_type.work);
- ap_queue_message(zdev->ap_dev, &ap_msg);
- rc = wait_for_completion_interruptible(&resp_type.work);
+
+ /**
+ * The target domain field within the cprb body/payload block will be
+ * replaced by the usage domain for non-management commands only.
+ * Therefore we check the first bit of the 'flags' parameter for
+ * management command indication.
+ * 0 - non management command
+ * 1 - management command
+ */
+ if (!((msg->cprbx.flags & 0x80) == 0x80)) {
+ msg->cprbx.target_id = (unsigned int)
+ AP_QID_QUEUE(zdev->ap_dev->qid);
+
+ if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
+ switch (msg->pld_lenfmt & 0x03) {
+ case 1:
+ lfmt = 2;
+ break;
+ case 2:
+ lfmt = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ lfmt = 1; /* length format #1 */
+ }
+ payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
+ payload_hdr->dom_val = (unsigned int)
+ AP_QID_QUEUE(zdev->ap_dev->qid);
+ }
+
+ init_completion(&rtype->work);
+ ap_queue_message(zdev->ap_dev, ap_msg);
+ rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
- rc = ap_msg.rc;
+ rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb);
+ rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb);
} else
/* Signal pending. */
- ap_cancel_message(zdev->ap_dev, &ap_msg);
+ ap_cancel_message(zdev->ap_dev, ap_msg);
-out_free:
- kzfree(ap_msg.message);
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
return rc;
}
+unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
+{
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_XCRB,
+ };
+
+ ap_init_message(ap_msg);
+ ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ if (!ap_msg->message)
+ return -ENOMEM;
+ ap_msg->receive = zcrypt_msgtype6_receive;
+ ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
+ if (!ap_msg->private) {
+ kzfree(ap_msg->message);
+ return -ENOMEM;
+ }
+ memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
+
+ rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
+
+ *func_code = HWRNG;
+ return 0;
+}
+
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to generate random data.
@@ -1081,36 +1266,36 @@ out_free:
* PCIXCC/CEX2C device to the request distributor
* @buffer: pointer to a memory page to return random data
*/
-
static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
- char *buffer)
+ char *buffer, struct ap_message *ap_msg)
{
- struct ap_message ap_msg;
- struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_XCRB,
- };
+ struct {
+ struct type6_hdr hdr;
+ struct CPRBX cprbx;
+ char function_code[2];
+ short int rule_length;
+ char rule[8];
+ short int verb_length;
+ short int key_length;
+ } __packed * msg = ap_msg->message;
+ struct response_type *rtype = (struct response_type *)(ap_msg->private);
int rc;
- ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
- if (!ap_msg.message)
- return -ENOMEM;
- ap_msg.receive = zcrypt_msgtype6_receive;
- ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
- atomic_inc_return(&zcrypt_step);
- ap_msg.private = &resp_type;
- rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
- init_completion(&resp_type.work);
- ap_queue_message(zdev->ap_dev, &ap_msg);
- rc = wait_for_completion_interruptible(&resp_type.work);
+ msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+
+ init_completion(&rtype->work);
+ ap_queue_message(zdev->ap_dev, ap_msg);
+ rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
- rc = ap_msg.rc;
+ rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_rng(zdev, &ap_msg, buffer);
+ rc = convert_response_rng(zdev, ap_msg, buffer);
} else
/* Signal pending. */
- ap_cancel_message(zdev->ap_dev, &ap_msg);
- kfree(ap_msg.message);
+ ap_cancel_message(zdev->ap_dev, ap_msg);
+
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
return rc;
}
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h
index 5750c4377bfa..a360dbe3c7d2 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.h
+++ b/drivers/s390/crypto/zcrypt_msgtype6.h
@@ -116,15 +116,25 @@ struct type86_fmt2_ext {
unsigned int offset4; /* 0x00000000 */
} __packed;
+unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, int *);
+unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, int *);
+unsigned int get_rng_fc(struct ap_message *, int *);
+
+#define LOW 10
+#define MEDIUM 100
+#define HIGH 500
+
+int speed_idx_cca(int);
+int speed_idx_ep11(int);
+
/**
* Prepare a type6 CPRB message for random number generation
*
* @ap_dev: AP device pointer
* @ap_msg: pointer to AP message
*/
-static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev,
- struct ap_message *ap_msg,
- unsigned random_number_length)
+static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg,
+ unsigned int random_number_length)
{
struct {
struct type6_hdr hdr;
@@ -156,7 +166,6 @@ static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev,
msg->hdr.FromCardLen2 = random_number_length,
msg->cprbx = local_cprbx;
msg->cprbx.rpl_datal = random_number_length,
- msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
memcpy(msg->function_code, msg->hdr.function_code, 0x02);
msg->rule_length = 0x0a;
memcpy(msg->rule, "RANDOM ", 8);
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 8491541f72cf..43de39c74944 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -46,11 +46,6 @@
#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */
-#define PCIXCC_MCL2_SPEED_RATING 7870
-#define PCIXCC_MCL3_SPEED_RATING 7870
-#define CEX2C_SPEED_RATING 7000
-#define CEX3C_SPEED_RATING 6500
-
#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
@@ -220,6 +215,15 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
struct type86_fmt2_ext fmt2;
struct CPRBX cprbx;
} __attribute__((packed)) *reply;
+ struct {
+ struct type6_hdr hdr;
+ struct CPRBX cprbx;
+ char function_code[2];
+ short int rule_length;
+ char rule[8];
+ short int verb_length;
+ short int key_length;
+ } __packed * msg;
int rc, i;
ap_init_message(&ap_msg);
@@ -227,7 +231,11 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
if (!ap_msg.message)
return -ENOMEM;
- rng_type6CPRB_msgX(ap_dev, &ap_msg, 4);
+ rng_type6CPRB_msgX(&ap_msg, 4);
+
+ msg = ap_msg.message;
+ msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
+
rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message,
ap_msg.length);
if (rc)
@@ -267,6 +275,14 @@ out_free:
static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev;
+ /*
+ * Normalized speed ratings per crypto adapter
+ * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
+ */
+ int PCIXCC_MCL2_SPEED_IDX[] = {10, 10, 10, 10, 10, 10, 10, 10};
+ int PCIXCC_MCL3_SPEED_IDX[] = { 8, 8, 8, 8, 8, 8, 8, 8};
+ int CEX2C_SPEED_IDX[] = {1000, 1400, 2400, 1100, 1500, 2600, 100, 12};
+ int CEX3C_SPEED_IDX[] = { 500, 700, 1400, 550, 800, 1500, 80, 10};
int rc = 0;
zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
@@ -284,13 +300,15 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
zdev->user_space_type = rc;
if (rc == ZCRYPT_PCIXCC_MCL2) {
zdev->type_string = "PCIXCC_MCL2";
- zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
+ memcpy(zdev->speed_rating, PCIXCC_MCL2_SPEED_IDX,
+ sizeof(PCIXCC_MCL2_SPEED_IDX));
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
} else {
zdev->type_string = "PCIXCC_MCL3";
- zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;
+ memcpy(zdev->speed_rating, PCIXCC_MCL3_SPEED_IDX,
+ sizeof(PCIXCC_MCL3_SPEED_IDX));
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
@@ -299,7 +317,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
case AP_DEVICE_TYPE_CEX2C:
zdev->user_space_type = ZCRYPT_CEX2C;
zdev->type_string = "CEX2C";
- zdev->speed_rating = CEX2C_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX2C_SPEED_IDX,
+ sizeof(CEX2C_SPEED_IDX));
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
@@ -307,7 +326,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
case AP_DEVICE_TYPE_CEX3C:
zdev->user_space_type = ZCRYPT_CEX3C;
zdev->type_string = "CEX3C";
- zdev->speed_rating = CEX3C_SPEED_RATING;
+ memcpy(zdev->speed_rating, CEX3C_SPEED_IDX,
+ sizeof(CEX3C_SPEED_IDX));
zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
@@ -315,6 +335,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
default:
goto out_free;
}
+ zdev->load = zdev->speed_rating[0];
rc = zcrypt_pcixcc_rng_supported(ap_dev);
if (rc < 0) {