diff options
author | Ralph Wuerthner <rwuerthn@de.ibm.com> | 2008-04-17 01:46:15 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-04-17 01:47:02 -0400 |
commit | 2f7c8bd6dc6540aa3275c0ad9f657401985c00e9 (patch) | |
tree | 12cb12d661424d332ad960113c8849b3579e7e6a /drivers/s390/crypto/zcrypt_api.c | |
parent | 893f11286644780fc7d6d415e537644da7bdaaf8 (diff) |
[S390] zcrypt: add support for large random numbers
This patch allows user space applications to access large amounts of
truly random data. The random data source is the build-in hardware
random number generator on the CEX2C cards.
Signed-off-by: Ralph Wuerthner <rwuerthn@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers/s390/crypto/zcrypt_api.c')
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index e3625a47a596..b2740ff2e615 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/compat.h> | 36 | #include <linux/compat.h> |
37 | #include <asm/atomic.h> | 37 | #include <asm/atomic.h> |
38 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
39 | #include <linux/hw_random.h> | ||
39 | 40 | ||
40 | #include "zcrypt_api.h" | 41 | #include "zcrypt_api.h" |
41 | 42 | ||
@@ -52,6 +53,9 @@ static LIST_HEAD(zcrypt_device_list); | |||
52 | static int zcrypt_device_count = 0; | 53 | static int zcrypt_device_count = 0; |
53 | static atomic_t zcrypt_open_count = ATOMIC_INIT(0); | 54 | static atomic_t zcrypt_open_count = ATOMIC_INIT(0); |
54 | 55 | ||
56 | static int zcrypt_rng_device_add(void); | ||
57 | static void zcrypt_rng_device_remove(void); | ||
58 | |||
55 | /** | 59 | /** |
56 | * Device attributes common for all crypto devices. | 60 | * Device attributes common for all crypto devices. |
57 | */ | 61 | */ |
@@ -216,6 +220,22 @@ int zcrypt_device_register(struct zcrypt_device *zdev) | |||
216 | __zcrypt_increase_preference(zdev); | 220 | __zcrypt_increase_preference(zdev); |
217 | zcrypt_device_count++; | 221 | zcrypt_device_count++; |
218 | spin_unlock_bh(&zcrypt_device_lock); | 222 | spin_unlock_bh(&zcrypt_device_lock); |
223 | if (zdev->ops->rng) { | ||
224 | rc = zcrypt_rng_device_add(); | ||
225 | if (rc) | ||
226 | goto out_unregister; | ||
227 | } | ||
228 | return 0; | ||
229 | |||
230 | out_unregister: | ||
231 | spin_lock_bh(&zcrypt_device_lock); | ||
232 | zcrypt_device_count--; | ||
233 | list_del_init(&zdev->list); | ||
234 | spin_unlock_bh(&zcrypt_device_lock); | ||
235 | sysfs_remove_group(&zdev->ap_dev->device.kobj, | ||
236 | &zcrypt_device_attr_group); | ||
237 | put_device(&zdev->ap_dev->device); | ||
238 | zcrypt_device_put(zdev); | ||
219 | out: | 239 | out: |
220 | return rc; | 240 | return rc; |
221 | } | 241 | } |
@@ -226,6 +246,8 @@ EXPORT_SYMBOL(zcrypt_device_register); | |||
226 | */ | 246 | */ |
227 | void zcrypt_device_unregister(struct zcrypt_device *zdev) | 247 | void zcrypt_device_unregister(struct zcrypt_device *zdev) |
228 | { | 248 | { |
249 | if (zdev->ops->rng) | ||
250 | zcrypt_rng_device_remove(); | ||
229 | spin_lock_bh(&zcrypt_device_lock); | 251 | spin_lock_bh(&zcrypt_device_lock); |
230 | zcrypt_device_count--; | 252 | zcrypt_device_count--; |
231 | list_del_init(&zdev->list); | 253 | list_del_init(&zdev->list); |
@@ -427,6 +449,37 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) | |||
427 | return -ENODEV; | 449 | return -ENODEV; |
428 | } | 450 | } |
429 | 451 | ||
452 | static long zcrypt_rng(char *buffer) | ||
453 | { | ||
454 | struct zcrypt_device *zdev; | ||
455 | int rc; | ||
456 | |||
457 | spin_lock_bh(&zcrypt_device_lock); | ||
458 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
459 | if (!zdev->online || !zdev->ops->rng) | ||
460 | continue; | ||
461 | zcrypt_device_get(zdev); | ||
462 | get_device(&zdev->ap_dev->device); | ||
463 | zdev->request_count++; | ||
464 | __zcrypt_decrease_preference(zdev); | ||
465 | if (try_module_get(zdev->ap_dev->drv->driver.owner)) { | ||
466 | spin_unlock_bh(&zcrypt_device_lock); | ||
467 | rc = zdev->ops->rng(zdev, buffer); | ||
468 | spin_lock_bh(&zcrypt_device_lock); | ||
469 | module_put(zdev->ap_dev->drv->driver.owner); | ||
470 | } else | ||
471 | rc = -EAGAIN; | ||
472 | zdev->request_count--; | ||
473 | __zcrypt_increase_preference(zdev); | ||
474 | put_device(&zdev->ap_dev->device); | ||
475 | zcrypt_device_put(zdev); | ||
476 | spin_unlock_bh(&zcrypt_device_lock); | ||
477 | return rc; | ||
478 | } | ||
479 | spin_unlock_bh(&zcrypt_device_lock); | ||
480 | return -ENODEV; | ||
481 | } | ||
482 | |||
430 | static void zcrypt_status_mask(char status[AP_DEVICES]) | 483 | static void zcrypt_status_mask(char status[AP_DEVICES]) |
431 | { | 484 | { |
432 | struct zcrypt_device *zdev; | 485 | struct zcrypt_device *zdev; |
@@ -1041,6 +1094,73 @@ out: | |||
1041 | return count; | 1094 | return count; |
1042 | } | 1095 | } |
1043 | 1096 | ||
1097 | static int zcrypt_rng_device_count; | ||
1098 | static u32 *zcrypt_rng_buffer; | ||
1099 | static int zcrypt_rng_buffer_index; | ||
1100 | static DEFINE_MUTEX(zcrypt_rng_mutex); | ||
1101 | |||
1102 | static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) | ||
1103 | { | ||
1104 | int rc; | ||
1105 | |||
1106 | /** | ||
1107 | * We don't need locking here because the RNG API guarantees serialized | ||
1108 | * read method calls. | ||
1109 | */ | ||
1110 | if (zcrypt_rng_buffer_index == 0) { | ||
1111 | rc = zcrypt_rng((char *) zcrypt_rng_buffer); | ||
1112 | if (rc < 0) | ||
1113 | return -EIO; | ||
1114 | zcrypt_rng_buffer_index = rc / sizeof *data; | ||
1115 | } | ||
1116 | *data = zcrypt_rng_buffer[--zcrypt_rng_buffer_index]; | ||
1117 | return sizeof *data; | ||
1118 | } | ||
1119 | |||
1120 | static struct hwrng zcrypt_rng_dev = { | ||
1121 | .name = "zcrypt", | ||
1122 | .data_read = zcrypt_rng_data_read, | ||
1123 | }; | ||
1124 | |||
1125 | static int zcrypt_rng_device_add(void) | ||
1126 | { | ||
1127 | int rc = 0; | ||
1128 | |||
1129 | mutex_lock(&zcrypt_rng_mutex); | ||
1130 | if (zcrypt_rng_device_count == 0) { | ||
1131 | zcrypt_rng_buffer = (u32 *) get_zeroed_page(GFP_KERNEL); | ||
1132 | if (!zcrypt_rng_buffer) { | ||
1133 | rc = -ENOMEM; | ||
1134 | goto out; | ||
1135 | } | ||
1136 | zcrypt_rng_buffer_index = 0; | ||
1137 | rc = hwrng_register(&zcrypt_rng_dev); | ||
1138 | if (rc) | ||
1139 | goto out_free; | ||
1140 | zcrypt_rng_device_count = 1; | ||
1141 | } else | ||
1142 | zcrypt_rng_device_count++; | ||
1143 | mutex_unlock(&zcrypt_rng_mutex); | ||
1144 | return 0; | ||
1145 | |||
1146 | out_free: | ||
1147 | free_page((unsigned long) zcrypt_rng_buffer); | ||
1148 | out: | ||
1149 | mutex_unlock(&zcrypt_rng_mutex); | ||
1150 | return rc; | ||
1151 | } | ||
1152 | |||
1153 | static void zcrypt_rng_device_remove(void) | ||
1154 | { | ||
1155 | mutex_lock(&zcrypt_rng_mutex); | ||
1156 | zcrypt_rng_device_count--; | ||
1157 | if (zcrypt_rng_device_count == 0) { | ||
1158 | hwrng_unregister(&zcrypt_rng_dev); | ||
1159 | free_page((unsigned long) zcrypt_rng_buffer); | ||
1160 | } | ||
1161 | mutex_unlock(&zcrypt_rng_mutex); | ||
1162 | } | ||
1163 | |||
1044 | /** | 1164 | /** |
1045 | * The module initialization code. | 1165 | * The module initialization code. |
1046 | */ | 1166 | */ |