Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 88422
b: refs/heads/master
c: 2f7c8bd
h: refs/heads/master
v: v3
  • Loading branch information
Ralph Wuerthner authored and Heiko Carstens committed Apr 17, 2008
1 parent fae0476 commit 17749e6
Show file tree
Hide file tree
Showing 5 changed files with 328 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 893f11286644780fc7d6d415e537644da7bdaaf8
refs/heads/master: 2f7c8bd6dc6540aa3275c0ad9f657401985c00e9
1 change: 1 addition & 0 deletions trunk/drivers/crypto/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ config ZCRYPT
tristate "Support for PCI-attached cryptographic adapters"
depends on S390
select ZCRYPT_MONOLITHIC if ZCRYPT="y"
select HW_RANDOM
help
Select this option if you want to use a PCI-attached cryptographic
adapter like:
Expand Down
120 changes: 120 additions & 0 deletions trunk/drivers/s390/crypto/zcrypt_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <linux/compat.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <linux/hw_random.h>

#include "zcrypt_api.h"

Expand All @@ -52,6 +53,9 @@ static LIST_HEAD(zcrypt_device_list);
static int zcrypt_device_count = 0;
static atomic_t zcrypt_open_count = ATOMIC_INIT(0);

static int zcrypt_rng_device_add(void);
static void zcrypt_rng_device_remove(void);

/**
* Device attributes common for all crypto devices.
*/
Expand Down Expand Up @@ -216,6 +220,22 @@ int zcrypt_device_register(struct zcrypt_device *zdev)
__zcrypt_increase_preference(zdev);
zcrypt_device_count++;
spin_unlock_bh(&zcrypt_device_lock);
if (zdev->ops->rng) {
rc = zcrypt_rng_device_add();
if (rc)
goto out_unregister;
}
return 0;

out_unregister:
spin_lock_bh(&zcrypt_device_lock);
zcrypt_device_count--;
list_del_init(&zdev->list);
spin_unlock_bh(&zcrypt_device_lock);
sysfs_remove_group(&zdev->ap_dev->device.kobj,
&zcrypt_device_attr_group);
put_device(&zdev->ap_dev->device);
zcrypt_device_put(zdev);
out:
return rc;
}
Expand All @@ -226,6 +246,8 @@ EXPORT_SYMBOL(zcrypt_device_register);
*/
void zcrypt_device_unregister(struct zcrypt_device *zdev)
{
if (zdev->ops->rng)
zcrypt_rng_device_remove();
spin_lock_bh(&zcrypt_device_lock);
zcrypt_device_count--;
list_del_init(&zdev->list);
Expand Down Expand Up @@ -427,6 +449,37 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
return -ENODEV;
}

static long zcrypt_rng(char *buffer)
{
struct zcrypt_device *zdev;
int 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);
spin_unlock_bh(&zcrypt_device_lock);
return rc;
}
spin_unlock_bh(&zcrypt_device_lock);
return -ENODEV;
}

static void zcrypt_status_mask(char status[AP_DEVICES])
{
struct zcrypt_device *zdev;
Expand Down Expand Up @@ -1041,6 +1094,73 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer,
return count;
}

static int zcrypt_rng_device_count;
static u32 *zcrypt_rng_buffer;
static int zcrypt_rng_buffer_index;
static DEFINE_MUTEX(zcrypt_rng_mutex);

static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data)
{
int rc;

/**
* We don't need locking here because the RNG API guarantees serialized
* read method calls.
*/
if (zcrypt_rng_buffer_index == 0) {
rc = zcrypt_rng((char *) zcrypt_rng_buffer);
if (rc < 0)
return -EIO;
zcrypt_rng_buffer_index = rc / sizeof *data;
}
*data = zcrypt_rng_buffer[--zcrypt_rng_buffer_index];
return sizeof *data;
}

static struct hwrng zcrypt_rng_dev = {
.name = "zcrypt",
.data_read = zcrypt_rng_data_read,
};

static int zcrypt_rng_device_add(void)
{
int rc = 0;

mutex_lock(&zcrypt_rng_mutex);
if (zcrypt_rng_device_count == 0) {
zcrypt_rng_buffer = (u32 *) get_zeroed_page(GFP_KERNEL);
if (!zcrypt_rng_buffer) {
rc = -ENOMEM;
goto out;
}
zcrypt_rng_buffer_index = 0;
rc = hwrng_register(&zcrypt_rng_dev);
if (rc)
goto out_free;
zcrypt_rng_device_count = 1;
} else
zcrypt_rng_device_count++;
mutex_unlock(&zcrypt_rng_mutex);
return 0;

out_free:
free_page((unsigned long) zcrypt_rng_buffer);
out:
mutex_unlock(&zcrypt_rng_mutex);
return rc;
}

static void zcrypt_rng_device_remove(void)
{
mutex_lock(&zcrypt_rng_mutex);
zcrypt_rng_device_count--;
if (zcrypt_rng_device_count == 0) {
hwrng_unregister(&zcrypt_rng_dev);
free_page((unsigned long) zcrypt_rng_buffer);
}
mutex_unlock(&zcrypt_rng_mutex);
}

/**
* The module initialization code.
*/
Expand Down
8 changes: 8 additions & 0 deletions trunk/drivers/s390/crypto/zcrypt_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,21 @@ struct ica_z90_status {
#define ZCRYPT_CEX2C 5
#define ZCRYPT_CEX2A 6

/**
* Large random numbers are pulled in 4096 byte chunks from the crypto cards
* and stored in a page. Be carefull when increasing this buffer due to size
* limitations for AP requests.
*/
#define ZCRYPT_RNG_BUFFER_SIZE 4096

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 (*rng)(struct zcrypt_device *, char *);
};

struct zcrypt_device {
Expand Down
Loading

0 comments on commit 17749e6

Please sign in to comment.