提交 34a15167 编写于 作者: I Ingo Tuchscherer 提交者: Martin Schwidefsky

s390/zcrypt: Introduce workload balancing

Crypto requests are very different in complexity and thus runtime.
Also various crypto adapters are differ with regard to the execution
time. Crypto requests can be balanced much better when the request
type and eligible crypto adapters are rated in a more precise
granularity. Therefore, request weights and adapter speed rates for
dedicated requests will be introduced.
Signed-off-by: NIngo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com>
Signed-off-by: NMartin Schwidefsky <schwidefsky@de.ibm.com>
上级 9af3e04e
...@@ -151,18 +151,16 @@ static inline int zcrypt_process_rescan(void) ...@@ -151,18 +151,16 @@ static inline int zcrypt_process_rescan(void)
* Need to be called while holding the zcrypt device list lock. * 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. * 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 zcrypt_device *tmp;
struct list_head *l; struct list_head *l;
if (zdev->speed_rating == 0) zdev->load -= weight;
return;
for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) { for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) {
tmp = list_entry(l, struct zcrypt_device, list); tmp = list_entry(l, struct zcrypt_device, list);
if ((tmp->request_count + 1) * tmp->speed_rating <= if (tmp->load <= zdev->load)
(zdev->request_count + 1) * zdev->speed_rating &&
tmp->speed_rating != 0)
break; break;
} }
if (l == zdev->list.prev) if (l == zdev->list.prev)
...@@ -179,18 +177,16 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev) ...@@ -179,18 +177,16 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev)
* Need to be called while holding the zcrypt device list lock. * 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. * 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 zcrypt_device *tmp;
struct list_head *l; struct list_head *l;
if (zdev->speed_rating == 0) zdev->load += weight;
return;
for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) { for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) {
tmp = list_entry(l, struct zcrypt_device, list); tmp = list_entry(l, struct zcrypt_device, list);
if ((tmp->request_count + 1) * tmp->speed_rating > if (tmp->load > zdev->load)
(zdev->request_count + 1) * zdev->speed_rating ||
tmp->speed_rating == 0)
break; break;
} }
if (l == zdev->list.next) if (l == zdev->list.next)
...@@ -270,7 +266,7 @@ int zcrypt_device_register(struct zcrypt_device *zdev) ...@@ -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, ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid,
zdev->online); zdev->online);
list_add_tail(&zdev->list, &zcrypt_device_list); list_add_tail(&zdev->list, &zcrypt_device_list);
__zcrypt_increase_preference(zdev); __zcrypt_increase_preference(zdev, 0); /* sort devices acc. weight */
zcrypt_device_count++; zcrypt_device_count++;
spin_unlock_bh(&zcrypt_device_lock); spin_unlock_bh(&zcrypt_device_lock);
if (zdev->ops->rng) { if (zdev->ops->rng) {
...@@ -386,8 +382,9 @@ static int zcrypt_release(struct inode *inode, struct file *filp) ...@@ -386,8 +382,9 @@ static int zcrypt_release(struct inode *inode, struct file *filp)
*/ */
static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
{ {
struct zcrypt_device *zdev; struct zcrypt_device *zdev, *pref_zdev = NULL;
int rc; int rc;
unsigned int weight, func_code, pref_weight = 0;
if (mex->outputdatalength < mex->inputdatalength) if (mex->outputdatalength < mex->inputdatalength)
return -EINVAL; return -EINVAL;
...@@ -398,6 +395,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) ...@@ -398,6 +395,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
*/ */
mex->outputdatalength = mex->inputdatalength; mex->outputdatalength = mex->inputdatalength;
rc = get_rsa_modex_fc(mex, &func_code);
if (rc)
return rc;
spin_lock_bh(&zcrypt_device_lock); spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) { list_for_each_entry(zdev, &zcrypt_device_list, list) {
if (!zdev->online || if (!zdev->online ||
...@@ -405,34 +406,52 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) ...@@ -405,34 +406,52 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
zdev->min_mod_size > mex->inputdatalength || zdev->min_mod_size > mex->inputdatalength ||
zdev->max_mod_size < mex->inputdatalength) zdev->max_mod_size < mex->inputdatalength)
continue; continue;
zcrypt_device_get(zdev); weight = zdev->speed_rating[func_code];
get_device(&zdev->ap_dev->device); if (!pref_zdev) {
zdev->request_count++; pref_zdev = zdev;
__zcrypt_decrease_preference(zdev); pref_weight = weight;
if (try_module_get(zdev->ap_dev->drv->driver.owner)) { continue;
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);
} }
else if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
rc = -EAGAIN; pref_zdev = zdev;
zdev->request_count--; pref_weight = weight;
__zcrypt_increase_preference(zdev); continue;
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); 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); spin_unlock_bh(&zcrypt_device_lock);
return -ENODEV; return rc;
} }
static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) 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; unsigned long long z1, z2, z3;
int rc, copied; int rc, copied;
unsigned int weight, func_code, pref_weight = 0;
if (crt->outputdatalength < crt->inputdatalength) if (crt->outputdatalength < crt->inputdatalength)
return -EINVAL; return -EINVAL;
...@@ -443,6 +462,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) ...@@ -443,6 +462,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
*/ */
crt->outputdatalength = crt->inputdatalength; crt->outputdatalength = crt->inputdatalength;
rc = get_rsa_crt_fc(crt, &func_code);
if (rc)
return rc;
copied = 0; copied = 0;
restart: restart:
spin_lock_bh(&zcrypt_device_lock); spin_lock_bh(&zcrypt_device_lock);
...@@ -489,33 +512,54 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) ...@@ -489,33 +512,54 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
/* The device can't handle this request. */ /* The device can't handle this request. */
continue; continue;
} }
zcrypt_device_get(zdev);
get_device(&zdev->ap_dev->device); weight = zdev->speed_rating[func_code];
zdev->request_count++; if (!pref_zdev) {
__zcrypt_decrease_preference(zdev); pref_zdev = zdev;
if (try_module_get(zdev->ap_dev->drv->driver.owner)) { pref_weight = weight;
spin_unlock_bh(&zcrypt_device_lock); continue;
rc = zdev->ops->rsa_modexpo_crt(zdev, crt); }
spin_lock_bh(&zcrypt_device_lock); if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
module_put(zdev->ap_dev->drv->driver.owner); pref_zdev = zdev;
pref_weight = weight;
continue;
} }
else if ((pref_zdev->load + pref_weight) <= zdev->load)
rc = -EAGAIN; break; /* Load on remaining devices too high - abort */
zdev->request_count--; }
__zcrypt_increase_preference(zdev); if (!pref_zdev) {
put_device(&zdev->ap_dev->device);
zcrypt_device_put(zdev);
spin_unlock_bh(&zcrypt_device_lock); 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); spin_unlock_bh(&zcrypt_device_lock);
return -ENODEV; return rc;
} }
static long zcrypt_send_cprb(struct ica_xcRB *xcRB) 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; 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); spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) { list_for_each_entry(zdev, &zcrypt_device_list, list) {
...@@ -524,27 +568,42 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) ...@@ -524,27 +568,42 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
(xcRB->user_defined != AUTOSELECT && (xcRB->user_defined != AUTOSELECT &&
AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)) AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined))
continue; continue;
zcrypt_device_get(zdev);
get_device(&zdev->ap_dev->device); weight = speed_idx_cca(func_code) * zdev->speed_rating[SECKEY];
zdev->request_count++; if (!pref_zdev) {
__zcrypt_decrease_preference(zdev); pref_zdev = zdev;
if (try_module_get(zdev->ap_dev->drv->driver.owner)) { pref_weight = weight;
spin_unlock_bh(&zcrypt_device_lock); continue;
rc = zdev->ops->send_cprb(zdev, xcRB); }
spin_lock_bh(&zcrypt_device_lock); if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
module_put(zdev->ap_dev->drv->driver.owner); pref_zdev = zdev;
pref_weight = weight;
continue;
} }
else if ((pref_zdev->load + pref_weight) <= zdev->load)
rc = -EAGAIN; break; /* Load on remaining devices too high - abort */
zdev->request_count--; }
__zcrypt_increase_preference(zdev); if (!pref_zdev) {
put_device(&zdev->ap_dev->device);
zcrypt_device_put(zdev);
spin_unlock_bh(&zcrypt_device_lock); 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); spin_unlock_bh(&zcrypt_device_lock);
return -ENODEV; return rc;
} }
struct ep11_target_dev_list { struct ep11_target_dev_list {
...@@ -568,7 +627,9 @@ static bool is_desired_ep11dev(unsigned int dev_qid, ...@@ -568,7 +627,9 @@ static bool is_desired_ep11dev(unsigned int dev_qid,
static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) 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; bool autoselect = false;
int rc; int rc;
struct ep11_target_dev_list ep11_dev_list = { struct ep11_target_dev_list ep11_dev_list = {
...@@ -596,6 +657,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) ...@@ -596,6 +657,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
return -EFAULT; return -EFAULT;
} }
rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code);
if (rc)
return rc;
spin_lock_bh(&zcrypt_device_lock); spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) { list_for_each_entry(zdev, &zcrypt_device_list, list) {
/* check if device is eligible */ /* check if device is eligible */
...@@ -608,58 +673,93 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) ...@@ -608,58 +673,93 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
!autoselect) !autoselect)
continue; continue;
zcrypt_device_get(zdev); weight = speed_idx_ep11(func_code) * zdev->speed_rating[SECKEY];
get_device(&zdev->ap_dev->device); if (!pref_zdev) {
zdev->request_count++; pref_zdev = zdev;
__zcrypt_decrease_preference(zdev); pref_weight = weight;
if (try_module_get(zdev->ap_dev->drv->driver.owner)) { continue;
spin_unlock_bh(&zcrypt_device_lock); }
rc = zdev->ops->send_ep11_cprb(zdev, xcrb); if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
spin_lock_bh(&zcrypt_device_lock); pref_zdev = zdev;
module_put(zdev->ap_dev->drv->driver.owner); pref_weight = weight;
} else { continue;
rc = -EAGAIN; }
} if ((pref_zdev->load + pref_weight) <= zdev->load)
zdev->request_count--; break; /* Load on remaining devices too high - abort */
__zcrypt_increase_preference(zdev); }
put_device(&zdev->ap_dev->device); if (!pref_zdev) {
zcrypt_device_put(zdev);
spin_unlock_bh(&zcrypt_device_lock); 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); spin_unlock_bh(&zcrypt_device_lock);
return -ENODEV; return rc;
} }
static long zcrypt_rng(char *buffer) 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; int rc;
rc = get_rng_fc(&ap_msg, &func_code);
if (rc)
return rc;
spin_lock_bh(&zcrypt_device_lock); spin_lock_bh(&zcrypt_device_lock);
list_for_each_entry(zdev, &zcrypt_device_list, list) { list_for_each_entry(zdev, &zcrypt_device_list, list) {
if (!zdev->online || !zdev->ops->rng) if (!zdev->online || !zdev->ops->rng)
continue; continue;
zcrypt_device_get(zdev);
get_device(&zdev->ap_dev->device); weight = zdev->speed_rating[func_code];
zdev->request_count++; if (!pref_zdev) {
__zcrypt_decrease_preference(zdev); pref_zdev = zdev;
if (try_module_get(zdev->ap_dev->drv->driver.owner)) { pref_weight = weight;
spin_unlock_bh(&zcrypt_device_lock); continue;
rc = zdev->ops->rng(zdev, buffer); }
spin_lock_bh(&zcrypt_device_lock); if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
module_put(zdev->ap_dev->drv->driver.owner); pref_zdev = zdev;
} else pref_weight = weight;
rc = -EAGAIN; continue;
zdev->request_count--; }
__zcrypt_increase_preference(zdev); if ((pref_zdev->load + pref_weight) <= zdev->load)
put_device(&zdev->ap_dev->device); break; /* Load on remaining devices too high - abort */
zcrypt_device_put(zdev); }
if (!pref_zdev) {
spin_unlock_bh(&zcrypt_device_lock); 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); spin_unlock_bh(&zcrypt_device_lock);
return -ENODEV; return rc;
} }
static void zcrypt_status_mask(char status[AP_DEVICES]) static void zcrypt_status_mask(char status[AP_DEVICES])
......
...@@ -84,15 +84,32 @@ struct ica_z90_status { ...@@ -84,15 +84,32 @@ struct ica_z90_status {
*/ */
#define ZCRYPT_RNG_BUFFER_SIZE 4096 #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_device;
struct zcrypt_ops { struct zcrypt_ops {
long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *); long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
long (*rsa_modexpo_crt)(struct zcrypt_device *, long (*rsa_modexpo_crt)(struct zcrypt_device *,
struct ica_rsa_modexpo_crt *); struct ica_rsa_modexpo_crt *);
long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *,
long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *); struct ap_message *);
long (*rng)(struct zcrypt_device *, char *); 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 list_head list; /* zcrypt ops list. */
struct module *owner; struct module *owner;
int variant; int variant;
...@@ -112,7 +129,8 @@ struct zcrypt_device { ...@@ -112,7 +129,8 @@ struct zcrypt_device {
int min_mod_size; /* Min number of bits. */ int min_mod_size; /* Min number of bits. */
int max_mod_size; /* Max number of bits. */ int max_mod_size; /* Max number of bits. */
int short_crt; /* Card has crt length restriction. */ 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. */ int request_count; /* # current requests. */
......
...@@ -43,9 +43,6 @@ ...@@ -43,9 +43,6 @@
#define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE #define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE
#define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ #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_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */
#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ #define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
...@@ -87,6 +84,8 @@ static struct ap_driver zcrypt_cex2a_driver = { ...@@ -87,6 +84,8 @@ static struct ap_driver zcrypt_cex2a_driver = {
static int zcrypt_cex2a_probe(struct ap_device *ap_dev) static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
{ {
struct zcrypt_device *zdev = NULL; 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; int rc = 0;
switch (ap_dev->device_type) { switch (ap_dev->device_type) {
...@@ -99,7 +98,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) ...@@ -99,7 +98,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
zdev->short_crt = 1; 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; zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
break; break;
case AP_DEVICE_TYPE_CEX3A: case AP_DEVICE_TYPE_CEX3A:
...@@ -117,7 +117,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) ...@@ -117,7 +117,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
} }
zdev->short_crt = 1; zdev->short_crt = 1;
zdev->speed_rating = CEX3A_SPEED_RATING; memcpy(zdev->speed_rating, CEX3A_SPEED_IDX,
sizeof(CEX3A_SPEED_IDX));
break; break;
} }
if (!zdev) if (!zdev)
...@@ -125,6 +126,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) ...@@ -125,6 +126,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
zdev->ap_dev = ap_dev; zdev->ap_dev = ap_dev;
zdev->online = 1; zdev->online = 1;
zdev->load = zdev->speed_rating[0];
ap_device_init_reply(ap_dev, &zdev->reply); ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev; ap_dev->private = zdev;
rc = zcrypt_device_register(zdev); rc = zcrypt_device_register(zdev);
......
...@@ -24,13 +24,6 @@ ...@@ -24,13 +24,6 @@
#define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */ #define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */
#define CEX4C_MAX_MOD_SIZE 512 /* 4096 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 CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE
#define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE
...@@ -71,6 +64,16 @@ static struct ap_driver zcrypt_cex4_driver = { ...@@ -71,6 +64,16 @@ static struct ap_driver zcrypt_cex4_driver = {
static int zcrypt_cex4_probe(struct ap_device *ap_dev) static int zcrypt_cex4_probe(struct ap_device *ap_dev)
{ {
struct zcrypt_device *zdev = NULL; 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; int rc = 0;
switch (ap_dev->device_type) { switch (ap_dev->device_type) {
...@@ -82,10 +85,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) ...@@ -82,10 +85,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENOMEM; return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4A"; zdev->type_string = "CEX4A";
zdev->speed_rating = CEX4A_SPEED_RATING; memcpy(zdev->speed_rating, CEX4A_SPEED_IDX,
sizeof(CEX4A_SPEED_IDX));
} else { } else {
zdev->type_string = "CEX5A"; 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->user_space_type = ZCRYPT_CEX3A;
zdev->min_mod_size = CEX4A_MIN_MOD_SIZE; zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
...@@ -110,10 +115,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) ...@@ -110,10 +115,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENOMEM; return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4C"; zdev->type_string = "CEX4C";
zdev->speed_rating = CEX4C_SPEED_RATING; memcpy(zdev->speed_rating, CEX4C_SPEED_IDX,
sizeof(CEX4C_SPEED_IDX));
} else { } else {
zdev->type_string = "CEX5C"; 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->user_space_type = ZCRYPT_CEX3C;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
...@@ -128,10 +135,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) ...@@ -128,10 +135,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENOMEM; return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4P"; zdev->type_string = "CEX4P";
zdev->speed_rating = CEX4P_SPEED_RATING; memcpy(zdev->speed_rating, CEX4P_SPEED_IDX,
sizeof(CEX4P_SPEED_IDX));
} else { } else {
zdev->type_string = "CEX5P"; 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->user_space_type = ZCRYPT_CEX4;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
...@@ -147,6 +156,7 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) ...@@ -147,6 +156,7 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
return -ENODEV; return -ENODEV;
zdev->ap_dev = ap_dev; zdev->ap_dev = ap_dev;
zdev->online = 1; zdev->online = 1;
zdev->load = zdev->speed_rating[0];
ap_device_init_reply(ap_dev, &zdev->reply); ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev; ap_dev->private = zdev;
rc = zcrypt_device_register(zdev); rc = zcrypt_device_register(zdev);
......
...@@ -173,6 +173,38 @@ struct type80_hdr { ...@@ -173,6 +173,38 @@ struct type80_hdr {
unsigned char reserved3[8]; unsigned char reserved3[8];
} __packed; } __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. * Convert a ICAMEX message to a type50 MEX message.
* *
......
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
#define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/ #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_init(void);
void zcrypt_msgtype50_exit(void); void zcrypt_msgtype50_exit(void);
......
...@@ -149,6 +149,112 @@ static struct CPRBX static_cprbx = { ...@@ -149,6 +149,112 @@ static struct CPRBX static_cprbx = {
.func_id = {0x54, 0x32}, .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. * Convert a ICAMEX message to a type6 MEX message.
* *
...@@ -297,9 +403,9 @@ struct type86_fmt2_msg { ...@@ -297,9 +403,9 @@ struct type86_fmt2_msg {
struct type86_fmt2_ext fmt2; struct type86_fmt2_ext fmt2;
} __packed; } __packed;
static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
struct ap_message *ap_msg, struct ica_xcRB *xcRB,
struct ica_xcRB *xcRB) unsigned int *fcode)
{ {
static struct type6_hdr static_type6_hdrX = { static struct type6_hdr static_type6_hdrX = {
.type = 0x06, .type = 0x06,
...@@ -379,6 +485,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, ...@@ -379,6 +485,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
memcpy(msg->hdr.function_code, function_code, memcpy(msg->hdr.function_code, function_code,
sizeof(msg->hdr.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) if (memcmp(function_code, "US", 2) == 0)
ap_msg->special = 1; ap_msg->special = 1;
else else
...@@ -392,12 +500,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, ...@@ -392,12 +500,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
return 0; return 0;
} }
static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
struct ap_message *ap_msg, struct ep11_urb *xcRB,
struct ep11_urb *xcRB) unsigned int *fcode)
{ {
unsigned int lfmt;
static struct type6_hdr static_type6_ep11_hdr = { static struct type6_hdr static_type6_ep11_hdr = {
.type = 0x06, .type = 0x06,
.rqid = {0x00, 0x01}, .rqid = {0x00, 0x01},
...@@ -421,7 +527,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, ...@@ -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_tag; /* fixed value 0x4 */
unsigned char dom_len; /* fixed value 0x4 */ unsigned char dom_len; /* fixed value 0x4 */
unsigned int dom_val; /* domain id */ unsigned int dom_val; /* domain id */
} __packed * payload_hdr; } __packed * payload_hdr = NULL;
if (CEIL4(xcRB->req_len) < xcRB->req_len) if (CEIL4(xcRB->req_len) < xcRB->req_len)
return -EINVAL; /* overflow after alignment*/ return -EINVAL; /* overflow after alignment*/
...@@ -450,36 +556,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, ...@@ -450,36 +556,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
return -EFAULT; return -EFAULT;
} }
/* *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF);
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);
}
return 0; return 0;
} }
...@@ -989,6 +1066,36 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, ...@@ -989,6 +1066,36 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
return rc; 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 * The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to handle a send_cprb request. * device to handle a send_cprb request.
...@@ -997,37 +1104,55 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, ...@@ -997,37 +1104,55 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
* @xcRB: pointer to the send_cprb request buffer * @xcRB: pointer to the send_cprb request buffer
*/ */
static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, 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; int rc;
struct response_type *rtype = (struct response_type *)(ap_msg->private);
ap_init_message(&ap_msg); init_completion(&rtype->work);
ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); ap_queue_message(zdev->ap_dev, ap_msg);
if (!ap_msg.message) rc = wait_for_completion_interruptible(&rtype->work);
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);
if (rc == 0) { if (rc == 0) {
rc = ap_msg.rc; rc = ap_msg->rc;
if (rc == 0) if (rc == 0)
rc = convert_response_xcrb(zdev, &ap_msg, xcRB); rc = convert_response_xcrb(zdev, ap_msg, xcRB);
} else } else
/* Signal pending. */ /* 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_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; return rc;
} }
...@@ -1039,41 +1164,101 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, ...@@ -1039,41 +1164,101 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
* @xcRB: pointer to the ep11 user request block * @xcRB: pointer to the ep11 user request block
*/ */
static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, 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; 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) * The target domain field within the cprb body/payload block will be
return -ENOMEM; * replaced by the usage domain for non-management commands only.
ap_msg.receive = zcrypt_msgtype6_receive_ep11; * Therefore we check the first bit of the 'flags' parameter for
ap_msg.psmid = (((unsigned long long) current->pid) << 32) + * management command indication.
atomic_inc_return(&zcrypt_step); * 0 - non management command
ap_msg.private = &resp_type; * 1 - management command
rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb); */
if (rc) if (!((msg->cprbx.flags & 0x80) == 0x80)) {
goto out_free; msg->cprbx.target_id = (unsigned int)
init_completion(&resp_type.work); AP_QID_QUEUE(zdev->ap_dev->qid);
ap_queue_message(zdev->ap_dev, &ap_msg);
rc = wait_for_completion_interruptible(&resp_type.work); 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) { if (rc == 0) {
rc = ap_msg.rc; rc = ap_msg->rc;
if (rc == 0) if (rc == 0)
rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb); rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb);
} else } else
/* Signal pending. */ /* 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; 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 * The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to generate random data. * device to generate random data.
...@@ -1081,36 +1266,36 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, ...@@ -1081,36 +1266,36 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
* PCIXCC/CEX2C device to the request distributor * PCIXCC/CEX2C device to the request distributor
* @buffer: pointer to a memory page to return random data * @buffer: pointer to a memory page to return random data
*/ */
static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
char *buffer) char *buffer, struct ap_message *ap_msg)
{ {
struct ap_message ap_msg; struct {
struct response_type resp_type = { struct type6_hdr hdr;
.type = PCIXCC_RESPONSE_TYPE_XCRB, 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; int rc;
ap_init_message(&ap_msg); msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
if (!ap_msg.message) init_completion(&rtype->work);
return -ENOMEM; ap_queue_message(zdev->ap_dev, ap_msg);
ap_msg.receive = zcrypt_msgtype6_receive; rc = wait_for_completion_interruptible(&rtype->work);
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);
if (rc == 0) { if (rc == 0) {
rc = ap_msg.rc; rc = ap_msg->rc;
if (rc == 0) if (rc == 0)
rc = convert_response_rng(zdev, &ap_msg, buffer); rc = convert_response_rng(zdev, ap_msg, buffer);
} else } else
/* Signal pending. */ /* Signal pending. */
ap_cancel_message(zdev->ap_dev, &ap_msg); ap_cancel_message(zdev->ap_dev, ap_msg);
kfree(ap_msg.message);
kzfree(ap_msg->message);
kzfree(ap_msg->private);
return rc; return rc;
} }
......
...@@ -116,15 +116,25 @@ struct type86_fmt2_ext { ...@@ -116,15 +116,25 @@ struct type86_fmt2_ext {
unsigned int offset4; /* 0x00000000 */ unsigned int offset4; /* 0x00000000 */
} __packed; } __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 * Prepare a type6 CPRB message for random number generation
* *
* @ap_dev: AP device pointer * @ap_dev: AP device pointer
* @ap_msg: pointer to AP message * @ap_msg: pointer to AP message
*/ */
static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg,
struct ap_message *ap_msg, unsigned int random_number_length)
unsigned random_number_length)
{ {
struct { struct {
struct type6_hdr hdr; struct type6_hdr hdr;
...@@ -156,7 +166,6 @@ static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, ...@@ -156,7 +166,6 @@ static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev,
msg->hdr.FromCardLen2 = random_number_length, msg->hdr.FromCardLen2 = random_number_length,
msg->cprbx = local_cprbx; msg->cprbx = local_cprbx;
msg->cprbx.rpl_datal = random_number_length, 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); memcpy(msg->function_code, msg->hdr.function_code, 0x02);
msg->rule_length = 0x0a; msg->rule_length = 0x0a;
memcpy(msg->rule, "RANDOM ", 8); memcpy(msg->rule, "RANDOM ", 8);
......
...@@ -46,11 +46,6 @@ ...@@ -46,11 +46,6 @@
#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE #define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */ #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_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ #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) ...@@ -220,6 +215,15 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
struct type86_fmt2_ext fmt2; struct type86_fmt2_ext fmt2;
struct CPRBX cprbx; struct CPRBX cprbx;
} __attribute__((packed)) *reply; } __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; int rc, i;
ap_init_message(&ap_msg); ap_init_message(&ap_msg);
...@@ -227,7 +231,11 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) ...@@ -227,7 +231,11 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
if (!ap_msg.message) if (!ap_msg.message)
return -ENOMEM; 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, rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message,
ap_msg.length); ap_msg.length);
if (rc) if (rc)
...@@ -267,6 +275,14 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) ...@@ -267,6 +275,14 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
{ {
struct zcrypt_device *zdev; 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; int rc = 0;
zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
...@@ -284,13 +300,15 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) ...@@ -284,13 +300,15 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
zdev->user_space_type = rc; zdev->user_space_type = rc;
if (rc == ZCRYPT_PCIXCC_MCL2) { if (rc == ZCRYPT_PCIXCC_MCL2) {
zdev->type_string = "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->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
} else { } else {
zdev->type_string = "PCIXCC_MCL3"; 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->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = 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) ...@@ -299,7 +317,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
case AP_DEVICE_TYPE_CEX2C: case AP_DEVICE_TYPE_CEX2C:
zdev->user_space_type = ZCRYPT_CEX2C; zdev->user_space_type = ZCRYPT_CEX2C;
zdev->type_string = "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->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = 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) ...@@ -307,7 +326,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
case AP_DEVICE_TYPE_CEX3C: case AP_DEVICE_TYPE_CEX3C:
zdev->user_space_type = ZCRYPT_CEX3C; zdev->user_space_type = ZCRYPT_CEX3C;
zdev->type_string = "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->min_mod_size = CEX3C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX3C_MAX_MOD_SIZE; zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
zdev->max_exp_bit_length = 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) ...@@ -315,6 +335,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
default: default:
goto out_free; goto out_free;
} }
zdev->load = zdev->speed_rating[0];
rc = zcrypt_pcixcc_rng_supported(ap_dev); rc = zcrypt_pcixcc_rng_supported(ap_dev);
if (rc < 0) { if (rc < 0) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册