aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto/zcrypt_api.c
diff options
context:
space:
mode:
authorRalph Wuerthner <rwuerthn@de.ibm.com>2008-04-17 01:46:15 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-04-17 01:47:02 -0400
commit2f7c8bd6dc6540aa3275c0ad9f657401985c00e9 (patch)
tree12cb12d661424d332ad960113c8849b3579e7e6a /drivers/s390/crypto/zcrypt_api.c
parent893f11286644780fc7d6d415e537644da7bdaaf8 (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.c120
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);
52static int zcrypt_device_count = 0; 53static int zcrypt_device_count = 0;
53static atomic_t zcrypt_open_count = ATOMIC_INIT(0); 54static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
54 55
56static int zcrypt_rng_device_add(void);
57static 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
230out_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);
219out: 239out:
220 return rc; 240 return rc;
221} 241}
@@ -226,6 +246,8 @@ EXPORT_SYMBOL(zcrypt_device_register);
226 */ 246 */
227void zcrypt_device_unregister(struct zcrypt_device *zdev) 247void 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
452static 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
430static void zcrypt_status_mask(char status[AP_DEVICES]) 483static 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
1097static int zcrypt_rng_device_count;
1098static u32 *zcrypt_rng_buffer;
1099static int zcrypt_rng_buffer_index;
1100static DEFINE_MUTEX(zcrypt_rng_mutex);
1101
1102static 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
1120static struct hwrng zcrypt_rng_dev = {
1121 .name = "zcrypt",
1122 .data_read = zcrypt_rng_data_read,
1123};
1124
1125static 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
1146out_free:
1147 free_page((unsigned long) zcrypt_rng_buffer);
1148out:
1149 mutex_unlock(&zcrypt_rng_mutex);
1150 return rc;
1151}
1152
1153static 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 */