summaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto')
-rw-r--r--drivers/s390/crypto/zcrypt_api.c253
-rw-r--r--drivers/s390/crypto/zcrypt_api.h14
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c6
-rw-r--r--drivers/s390/crypto/zcrypt_cex2c.c6
-rw-r--r--drivers/s390/crypto/zcrypt_cex4.c58
5 files changed, 213 insertions, 124 deletions
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index a711728c3857..223e1c233278 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -602,13 +602,13 @@ static inline bool zcrypt_card_compare(struct zcrypt_card *zc,
unsigned int pref_weight)
{
if (!pref_zc)
- return false;
+ return true;
weight += atomic_read(&zc->load);
pref_weight += atomic_read(&pref_zc->load);
if (weight == pref_weight)
- return atomic64_read(&zc->card->total_request_count) >
+ return atomic64_read(&zc->card->total_request_count) <
atomic64_read(&pref_zc->card->total_request_count);
- return weight > pref_weight;
+ return weight < pref_weight;
}
static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
@@ -617,26 +617,27 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
unsigned int pref_weight)
{
if (!pref_zq)
- return false;
+ return true;
weight += atomic_read(&zq->load);
pref_weight += atomic_read(&pref_zq->load);
if (weight == pref_weight)
- return zq->queue->total_request_count >
+ return zq->queue->total_request_count <
pref_zq->queue->total_request_count;
- return weight > pref_weight;
+ return weight < pref_weight;
}
/*
* zcrypt ioctls.
*/
static long zcrypt_rsa_modexpo(struct ap_perms *perms,
+ struct zcrypt_track *tr,
struct ica_rsa_modexpo *mex)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
- unsigned int weight = 0, pref_weight = 0;
+ unsigned int wgt = 0, pref_wgt = 0;
unsigned int func_code;
- int qid = 0, rc = -ENODEV;
+ int cpen, qpen, qid = 0, rc = -ENODEV;
struct module *mod;
trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO);
@@ -673,8 +674,12 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
- weight = zc->speed_rating[func_code];
- if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
+ wgt = zc->speed_rating[func_code];
+ /* penalty if this msg was previously sent via this card */
+ cpen = (tr && tr->again_counter && tr->last_qid &&
+ AP_QID_CARD(tr->last_qid) == zc->card->id) ?
+ TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
+ if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
continue;
for_each_zcrypt_queue(zq, zc) {
/* check if device is online and eligible */
@@ -684,15 +689,19 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
- if (zcrypt_queue_compare(zq, pref_zq,
- weight, pref_weight))
+ /* penalty if the msg was previously sent at this qid */
+ qpen = (tr && tr->again_counter && tr->last_qid &&
+ tr->last_qid == zq->queue->qid) ?
+ TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
+ if (!zcrypt_queue_compare(zq, pref_zq,
+ wgt + cpen + qpen, pref_wgt))
continue;
pref_zc = zc;
pref_zq = zq;
- pref_weight = weight;
+ pref_wgt = wgt + cpen + qpen;
}
}
- pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight);
+ pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
spin_unlock(&zcrypt_list_lock);
if (!pref_zq) {
@@ -704,23 +713,28 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
rc = pref_zq->ops->rsa_modexpo(pref_zq, mex);
spin_lock(&zcrypt_list_lock);
- zcrypt_drop_queue(pref_zc, pref_zq, mod, weight);
+ zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
spin_unlock(&zcrypt_list_lock);
out:
+ if (tr) {
+ tr->last_rc = rc;
+ tr->last_qid = qid;
+ }
trace_s390_zcrypt_rep(mex, func_code, rc,
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
return rc;
}
static long zcrypt_rsa_crt(struct ap_perms *perms,
+ struct zcrypt_track *tr,
struct ica_rsa_modexpo_crt *crt)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
- unsigned int weight = 0, pref_weight = 0;
+ unsigned int wgt = 0, pref_wgt = 0;
unsigned int func_code;
- int qid = 0, rc = -ENODEV;
+ int cpen, qpen, qid = 0, rc = -ENODEV;
struct module *mod;
trace_s390_zcrypt_req(crt, TP_ICARSACRT);
@@ -757,8 +771,12 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
- weight = zc->speed_rating[func_code];
- if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
+ wgt = zc->speed_rating[func_code];
+ /* penalty if this msg was previously sent via this card */
+ cpen = (tr && tr->again_counter && tr->last_qid &&
+ AP_QID_CARD(tr->last_qid) == zc->card->id) ?
+ TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
+ if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
continue;
for_each_zcrypt_queue(zq, zc) {
/* check if device is online and eligible */
@@ -768,15 +786,19 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
- if (zcrypt_queue_compare(zq, pref_zq,
- weight, pref_weight))
+ /* penalty if the msg was previously sent at this qid */
+ qpen = (tr && tr->again_counter && tr->last_qid &&
+ tr->last_qid == zq->queue->qid) ?
+ TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
+ if (!zcrypt_queue_compare(zq, pref_zq,
+ wgt + cpen + qpen, pref_wgt))
continue;
pref_zc = zc;
pref_zq = zq;
- pref_weight = weight;
+ pref_wgt = wgt + cpen + qpen;
}
}
- pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight);
+ pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
spin_unlock(&zcrypt_list_lock);
if (!pref_zq) {
@@ -788,25 +810,30 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt);
spin_lock(&zcrypt_list_lock);
- zcrypt_drop_queue(pref_zc, pref_zq, mod, weight);
+ zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
spin_unlock(&zcrypt_list_lock);
out:
+ if (tr) {
+ tr->last_rc = rc;
+ tr->last_qid = qid;
+ }
trace_s390_zcrypt_rep(crt, func_code, rc,
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
return rc;
}
static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
+ struct zcrypt_track *tr,
struct ica_xcRB *xcRB)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
struct ap_message ap_msg;
- unsigned int weight = 0, pref_weight = 0;
+ unsigned int wgt = 0, pref_wgt = 0;
unsigned int func_code;
unsigned short *domain, tdom;
- int qid = 0, rc = -ENODEV;
+ int cpen, qpen, qid = 0, rc = -ENODEV;
struct module *mod;
trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB);
@@ -843,8 +870,12 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
- weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
- if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
+ wgt = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
+ /* penalty if this msg was previously sent via this card */
+ cpen = (tr && tr->again_counter && tr->last_qid &&
+ AP_QID_CARD(tr->last_qid) == zc->card->id) ?
+ TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
+ if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
continue;
for_each_zcrypt_queue(zq, zc) {
/* check if device is online and eligible */
@@ -857,15 +888,19 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
- if (zcrypt_queue_compare(zq, pref_zq,
- weight, pref_weight))
+ /* penalty if the msg was previously sent at this qid */
+ qpen = (tr && tr->again_counter && tr->last_qid &&
+ tr->last_qid == zq->queue->qid) ?
+ TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
+ if (!zcrypt_queue_compare(zq, pref_zq,
+ wgt + cpen + qpen, pref_wgt))
continue;
pref_zc = zc;
pref_zq = zq;
- pref_weight = weight;
+ pref_wgt = wgt + cpen + qpen;
}
}
- pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight);
+ pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
spin_unlock(&zcrypt_list_lock);
if (!pref_zq) {
@@ -881,11 +916,15 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcRB, &ap_msg);
spin_lock(&zcrypt_list_lock);
- zcrypt_drop_queue(pref_zc, pref_zq, mod, weight);
+ zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
spin_unlock(&zcrypt_list_lock);
out:
ap_release_message(&ap_msg);
+ if (tr) {
+ tr->last_rc = rc;
+ tr->last_qid = qid;
+ }
trace_s390_zcrypt_rep(xcRB, func_code, rc,
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
return rc;
@@ -893,7 +932,7 @@ out:
long zcrypt_send_cprb(struct ica_xcRB *xcRB)
{
- return _zcrypt_send_cprb(false, &ap_perms, xcRB);
+ return _zcrypt_send_cprb(false, &ap_perms, NULL, xcRB);
}
EXPORT_SYMBOL(zcrypt_send_cprb);
@@ -925,16 +964,17 @@ static bool is_desired_ep11_queue(unsigned int dev_qid,
}
static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
+ struct zcrypt_track *tr,
struct ep11_urb *xcrb)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
struct ep11_target_dev *targets;
unsigned short target_num;
- unsigned int weight = 0, pref_weight = 0;
+ unsigned int wgt = 0, pref_wgt = 0;
unsigned int func_code;
struct ap_message ap_msg;
- int qid = 0, rc = -ENODEV;
+ int cpen, qpen, qid = 0, rc = -ENODEV;
struct module *mod;
trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB);
@@ -983,8 +1023,12 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
- weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
- if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
+ wgt = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
+ /* penalty if this msg was previously sent via this card */
+ cpen = (tr && tr->again_counter && tr->last_qid &&
+ AP_QID_CARD(tr->last_qid) == zc->card->id) ?
+ TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
+ if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
continue;
for_each_zcrypt_queue(zq, zc) {
/* check if device is online and eligible */
@@ -998,15 +1042,19 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
- if (zcrypt_queue_compare(zq, pref_zq,
- weight, pref_weight))
+ /* penalty if the msg was previously sent at this qid */
+ qpen = (tr && tr->again_counter && tr->last_qid &&
+ tr->last_qid == zq->queue->qid) ?
+ TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
+ if (!zcrypt_queue_compare(zq, pref_zq,
+ wgt + cpen + qpen, pref_wgt))
continue;
pref_zc = zc;
pref_zq = zq;
- pref_weight = weight;
+ pref_wgt = wgt + cpen + qpen;
}
}
- pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight);
+ pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
spin_unlock(&zcrypt_list_lock);
if (!pref_zq) {
@@ -1018,13 +1066,17 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
rc = pref_zq->ops->send_ep11_cprb(userspace, pref_zq, xcrb, &ap_msg);
spin_lock(&zcrypt_list_lock);
- zcrypt_drop_queue(pref_zc, pref_zq, mod, weight);
+ zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
spin_unlock(&zcrypt_list_lock);
out_free:
kfree(targets);
out:
ap_release_message(&ap_msg);
+ if (tr) {
+ tr->last_rc = rc;
+ tr->last_qid = qid;
+ }
trace_s390_zcrypt_rep(xcrb, func_code, rc,
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
return rc;
@@ -1032,7 +1084,7 @@ out:
long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
{
- return _zcrypt_send_ep11_cprb(false, &ap_perms, xcrb);
+ return _zcrypt_send_ep11_cprb(false, &ap_perms, NULL, xcrb);
}
EXPORT_SYMBOL(zcrypt_send_ep11_cprb);
@@ -1040,7 +1092,7 @@ static long zcrypt_rng(char *buffer)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
- unsigned int weight = 0, pref_weight = 0;
+ unsigned int wgt = 0, pref_wgt = 0;
unsigned int func_code;
struct ap_message ap_msg;
unsigned int domain;
@@ -1062,22 +1114,21 @@ static long zcrypt_rng(char *buffer)
if (!zc->online || !(zc->card->functions & 0x10000000))
continue;
/* get weight index of the card device */
- weight = zc->speed_rating[func_code];
- if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
+ wgt = zc->speed_rating[func_code];
+ if (!zcrypt_card_compare(zc, pref_zc, wgt, pref_wgt))
continue;
for_each_zcrypt_queue(zq, zc) {
/* check if device is online and eligible */
if (!zq->online || !zq->ops->rng)
continue;
- if (zcrypt_queue_compare(zq, pref_zq,
- weight, pref_weight))
+ if (!zcrypt_queue_compare(zq, pref_zq, wgt, pref_wgt))
continue;
pref_zc = zc;
pref_zq = zq;
- pref_weight = weight;
+ pref_wgt = wgt;
}
}
- pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight);
+ pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
spin_unlock(&zcrypt_list_lock);
if (!pref_zq) {
@@ -1089,7 +1140,7 @@ static long zcrypt_rng(char *buffer)
rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg);
spin_lock(&zcrypt_list_lock);
- zcrypt_drop_queue(pref_zc, pref_zq, mod, weight);
+ zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
spin_unlock(&zcrypt_list_lock);
out:
@@ -1301,19 +1352,25 @@ static int zcrypt_requestq_count(void)
static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg)
{
int rc;
+ struct zcrypt_track tr;
struct ica_rsa_modexpo mex;
struct ica_rsa_modexpo __user *umex = (void __user *) arg;
+ memset(&tr, 0, sizeof(tr));
if (copy_from_user(&mex, umex, sizeof(mex)))
return -EFAULT;
do {
- rc = zcrypt_rsa_modexpo(perms, &mex);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_modexpo(perms, &tr, &mex);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_modexpo(perms, &mex);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_modexpo(perms, &tr, &mex);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc);
return rc;
@@ -1324,19 +1381,25 @@ static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg)
static int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg)
{
int rc;
+ struct zcrypt_track tr;
struct ica_rsa_modexpo_crt crt;
struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg;
+ memset(&tr, 0, sizeof(tr));
if (copy_from_user(&crt, ucrt, sizeof(crt)))
return -EFAULT;
do {
- rc = zcrypt_rsa_crt(perms, &crt);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_crt(perms, &tr, &crt);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_crt(perms, &crt);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_crt(perms, &tr, &crt);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc);
return rc;
@@ -1348,18 +1411,24 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
{
int rc;
struct ica_xcRB xcRB;
+ struct zcrypt_track tr;
struct ica_xcRB __user *uxcRB = (void __user *) arg;
+ memset(&tr, 0, sizeof(tr));
if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
return -EFAULT;
do {
- rc = _zcrypt_send_cprb(true, perms, &xcRB);
- } while (rc == -EAGAIN);
+ rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = _zcrypt_send_cprb(true, perms, &xcRB);
- } while (rc == -EAGAIN);
+ rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
if (rc)
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n",
rc, xcRB.status);
@@ -1372,18 +1441,24 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
{
int rc;
struct ep11_urb xcrb;
+ struct zcrypt_track tr;
struct ep11_urb __user *uxcrb = (void __user *)arg;
+ memset(&tr, 0, sizeof(tr));
if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
return -EFAULT;
do {
- rc = _zcrypt_send_ep11_cprb(true, perms, &xcrb);
- } while (rc == -EAGAIN);
+ rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = _zcrypt_send_ep11_cprb(true, perms, &xcrb);
- } while (rc == -EAGAIN);
+ rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
if (rc)
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc);
if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
@@ -1535,8 +1610,10 @@ static long trans_modexpo32(struct ap_perms *perms, struct file *filp,
struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
struct compat_ica_rsa_modexpo mex32;
struct ica_rsa_modexpo mex64;
+ struct zcrypt_track tr;
long rc;
+ memset(&tr, 0, sizeof(tr));
if (copy_from_user(&mex32, umex32, sizeof(mex32)))
return -EFAULT;
mex64.inputdata = compat_ptr(mex32.inputdata);
@@ -1546,13 +1623,17 @@ static long trans_modexpo32(struct ap_perms *perms, struct file *filp,
mex64.b_key = compat_ptr(mex32.b_key);
mex64.n_modulus = compat_ptr(mex32.n_modulus);
do {
- rc = zcrypt_rsa_modexpo(perms, &mex64);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_modexpo(perms, &tr, &mex64);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_modexpo(perms, &mex64);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_modexpo(perms, &tr, &mex64);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
if (rc)
return rc;
return put_user(mex64.outputdatalength,
@@ -1577,8 +1658,10 @@ static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
struct compat_ica_rsa_modexpo_crt crt32;
struct ica_rsa_modexpo_crt crt64;
+ struct zcrypt_track tr;
long rc;
+ memset(&tr, 0, sizeof(tr));
if (copy_from_user(&crt32, ucrt32, sizeof(crt32)))
return -EFAULT;
crt64.inputdata = compat_ptr(crt32.inputdata);
@@ -1591,13 +1674,17 @@ static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
crt64.nq_prime = compat_ptr(crt32.nq_prime);
crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
do {
- rc = zcrypt_rsa_crt(perms, &crt64);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_crt(perms, &tr, &crt64);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_crt(perms, &crt64);
- } while (rc == -EAGAIN);
+ rc = zcrypt_rsa_crt(perms, &tr, &crt64);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
if (rc)
return rc;
return put_user(crt64.outputdatalength,
@@ -1629,9 +1716,11 @@ static long trans_xcRB32(struct ap_perms *perms, struct file *filp,
{
struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
struct compat_ica_xcRB xcRB32;
+ struct zcrypt_track tr;
struct ica_xcRB xcRB64;
long rc;
+ memset(&tr, 0, sizeof(tr));
if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32)))
return -EFAULT;
xcRB64.agent_ID = xcRB32.agent_ID;
@@ -1655,13 +1744,17 @@ static long trans_xcRB32(struct ap_perms *perms, struct file *filp,
xcRB64.priority_window = xcRB32.priority_window;
xcRB64.status = xcRB32.status;
do {
- rc = _zcrypt_send_cprb(true, perms, &xcRB64);
- } while (rc == -EAGAIN);
+ rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB64);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = _zcrypt_send_cprb(true, perms, &xcRB64);
- } while (rc == -EAGAIN);
+ rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB64);
+ if (rc == -EAGAIN)
+ tr.again_counter++;
+ } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
xcRB32.reply_data_length = xcRB64.reply_data_length;
xcRB32.status = xcRB64.status;
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 19ddfc38e029..263ed1735431 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -55,6 +55,18 @@ enum crypto_ops {
struct zcrypt_queue;
+/* struct to hold tracking information for a userspace request/response */
+struct zcrypt_track {
+ int again_counter; /* retry attempts counter */
+ int last_qid; /* last qid used */
+ int last_rc; /* last return code */
+};
+
+/* defines related to message tracking */
+#define TRACK_AGAIN_MAX 10
+#define TRACK_AGAIN_CARD_WEIGHT_PENALTY 1000
+#define TRACK_AGAIN_QUEUE_WEIGHT_PENALTY 10000
+
struct zcrypt_ops {
long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *);
long (*rsa_modexpo_crt)(struct zcrypt_queue *,
@@ -82,7 +94,7 @@ struct zcrypt_card {
int min_mod_size; /* Min number of bits. */
int max_mod_size; /* Max number of bits. */
int max_exp_bit_length;
- int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */
+ const int *speed_rating; /* Speed idx of crypto ops. */
atomic_t 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 b447f3e9e4a2..226a5612e855 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -94,8 +94,7 @@ static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev)
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->speed_rating = CEX2A_SPEED_IDX;
zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
zc->type_string = "CEX2A";
zc->user_space_type = ZCRYPT_CEX2A;
@@ -108,8 +107,7 @@ static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev)
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->speed_rating = CEX3A_SPEED_IDX;
zc->type_string = "CEX3A";
zc->user_space_type = ZCRYPT_CEX3A;
} else {
diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c
index 146eb9f24694..7a8cbdbe4408 100644
--- a/drivers/s390/crypto/zcrypt_cex2c.c
+++ b/drivers/s390/crypto/zcrypt_cex2c.c
@@ -266,8 +266,7 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev)
case AP_DEVICE_TYPE_CEX2C:
zc->user_space_type = ZCRYPT_CEX2C;
zc->type_string = "CEX2C";
- memcpy(zc->speed_rating, CEX2C_SPEED_IDX,
- sizeof(CEX2C_SPEED_IDX));
+ zc->speed_rating = CEX2C_SPEED_IDX;
zc->min_mod_size = CEX2C_MIN_MOD_SIZE;
zc->max_mod_size = CEX2C_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX2C_MAX_MOD_SIZE;
@@ -275,8 +274,7 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev)
case AP_DEVICE_TYPE_CEX3C:
zc->user_space_type = ZCRYPT_CEX3C;
zc->type_string = "CEX3C";
- memcpy(zc->speed_rating, CEX3C_SPEED_IDX,
- sizeof(CEX3C_SPEED_IDX));
+ zc->speed_rating = CEX3C_SPEED_IDX;
zc->min_mod_size = CEX3C_MIN_MOD_SIZE;
zc->max_mod_size = CEX3C_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index d9ebe3a3c210..f5195bca1d85 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -409,31 +409,31 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
* Normalized speed ratings per crypto adapter
* MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
*/
- static const int CEX4A_SPEED_IDX[] = {
+ static const int CEX4A_SPEED_IDX[NUM_OPS] = {
14, 19, 249, 42, 228, 1458, 0, 0};
- static const int CEX5A_SPEED_IDX[] = {
+ static const int CEX5A_SPEED_IDX[NUM_OPS] = {
8, 9, 20, 18, 66, 458, 0, 0};
- static const int CEX6A_SPEED_IDX[] = {
+ static const int CEX6A_SPEED_IDX[NUM_OPS] = {
6, 9, 20, 17, 65, 438, 0, 0};
- static const int CEX7A_SPEED_IDX[] = {
+ static const int CEX7A_SPEED_IDX[NUM_OPS] = {
6, 8, 17, 15, 54, 362, 0, 0};
- static const int CEX4C_SPEED_IDX[] = {
+ static const int CEX4C_SPEED_IDX[NUM_OPS] = {
59, 69, 308, 83, 278, 2204, 209, 40};
static const int CEX5C_SPEED_IDX[] = {
24, 31, 50, 37, 90, 479, 27, 10};
- static const int CEX6C_SPEED_IDX[] = {
+ static const int CEX6C_SPEED_IDX[NUM_OPS] = {
16, 20, 32, 27, 77, 455, 24, 9};
- static const int CEX7C_SPEED_IDX[] = {
+ static const int CEX7C_SPEED_IDX[NUM_OPS] = {
14, 16, 26, 23, 64, 376, 23, 8};
- static const int CEX4P_SPEED_IDX[] = {
+ static const int CEX4P_SPEED_IDX[NUM_OPS] = {
0, 0, 0, 0, 0, 0, 0, 50};
- static const int CEX5P_SPEED_IDX[] = {
+ static const int CEX5P_SPEED_IDX[NUM_OPS] = {
0, 0, 0, 0, 0, 0, 0, 10};
- static const int CEX6P_SPEED_IDX[] = {
+ static const int CEX6P_SPEED_IDX[NUM_OPS] = {
0, 0, 0, 0, 0, 0, 0, 9};
- static const int CEX7P_SPEED_IDX[] = {
+ static const int CEX7P_SPEED_IDX[NUM_OPS] = {
0, 0, 0, 0, 0, 0, 0, 8};
struct ap_card *ac = to_ap_card(&ap_dev->device);
@@ -449,26 +449,22 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
zc->type_string = "CEX4A";
zc->user_space_type = ZCRYPT_CEX4;
- memcpy(zc->speed_rating, CEX4A_SPEED_IDX,
- sizeof(CEX4A_SPEED_IDX));
+ zc->speed_rating = CEX4A_SPEED_IDX;
} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) {
zc->type_string = "CEX5A";
zc->user_space_type = ZCRYPT_CEX5;
- memcpy(zc->speed_rating, CEX5A_SPEED_IDX,
- sizeof(CEX5A_SPEED_IDX));
+ zc->speed_rating = CEX5A_SPEED_IDX;
} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX6) {
zc->type_string = "CEX6A";
zc->user_space_type = ZCRYPT_CEX6;
- memcpy(zc->speed_rating, CEX6A_SPEED_IDX,
- sizeof(CEX6A_SPEED_IDX));
+ zc->speed_rating = CEX6A_SPEED_IDX;
} else {
zc->type_string = "CEX7A";
/* wrong user space type, just for compatibility
* with the ZCRYPT_STATUS_MASK ioctl.
*/
zc->user_space_type = ZCRYPT_CEX6;
- memcpy(zc->speed_rating, CEX7A_SPEED_IDX,
- sizeof(CEX7A_SPEED_IDX));
+ zc->speed_rating = CEX7A_SPEED_IDX;
}
zc->min_mod_size = CEX4A_MIN_MOD_SIZE;
if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
@@ -488,32 +484,28 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
* just keep it for cca compatibility
*/
zc->user_space_type = ZCRYPT_CEX3C;
- memcpy(zc->speed_rating, CEX4C_SPEED_IDX,
- sizeof(CEX4C_SPEED_IDX));
+ zc->speed_rating = CEX4C_SPEED_IDX;
} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) {
zc->type_string = "CEX5C";
/* wrong user space type, must be CEX5
* just keep it for cca compatibility
*/
zc->user_space_type = ZCRYPT_CEX3C;
- memcpy(zc->speed_rating, CEX5C_SPEED_IDX,
- sizeof(CEX5C_SPEED_IDX));
+ zc->speed_rating = CEX5C_SPEED_IDX;
} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX6) {
zc->type_string = "CEX6C";
/* wrong user space type, must be CEX6
* just keep it for cca compatibility
*/
zc->user_space_type = ZCRYPT_CEX3C;
- memcpy(zc->speed_rating, CEX6C_SPEED_IDX,
- sizeof(CEX6C_SPEED_IDX));
+ zc->speed_rating = CEX6C_SPEED_IDX;
} else {
zc->type_string = "CEX7C";
/* wrong user space type, must be CEX7
* just keep it for cca compatibility
*/
zc->user_space_type = ZCRYPT_CEX3C;
- memcpy(zc->speed_rating, CEX7C_SPEED_IDX,
- sizeof(CEX7C_SPEED_IDX));
+ zc->speed_rating = CEX7C_SPEED_IDX;
}
zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
zc->max_mod_size = CEX4C_MAX_MOD_SIZE;
@@ -522,26 +514,22 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
zc->type_string = "CEX4P";
zc->user_space_type = ZCRYPT_CEX4;
- memcpy(zc->speed_rating, CEX4P_SPEED_IDX,
- sizeof(CEX4P_SPEED_IDX));
+ zc->speed_rating = CEX4P_SPEED_IDX;
} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) {
zc->type_string = "CEX5P";
zc->user_space_type = ZCRYPT_CEX5;
- memcpy(zc->speed_rating, CEX5P_SPEED_IDX,
- sizeof(CEX5P_SPEED_IDX));
+ zc->speed_rating = CEX5P_SPEED_IDX;
} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX6) {
zc->type_string = "CEX6P";
zc->user_space_type = ZCRYPT_CEX6;
- memcpy(zc->speed_rating, CEX6P_SPEED_IDX,
- sizeof(CEX6P_SPEED_IDX));
+ zc->speed_rating = CEX6P_SPEED_IDX;
} else {
zc->type_string = "CEX7P";
/* wrong user space type, just for compatibility
* with the ZCRYPT_STATUS_MASK ioctl.
*/
zc->user_space_type = ZCRYPT_CEX6;
- memcpy(zc->speed_rating, CEX7P_SPEED_IDX,
- sizeof(CEX7P_SPEED_IDX));
+ zc->speed_rating = CEX7P_SPEED_IDX;
}
zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
zc->max_mod_size = CEX4C_MAX_MOD_SIZE;