]>
Commit | Line | Data |
---|---|---|
812141a9 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e28d2af4 IT |
2 | /* |
3 | * zcrypt 2.1.0 | |
4 | * | |
5 | * Copyright IBM Corp. 2001, 2012 | |
6 | * Author(s): Robert Burroughs | |
7 | * Eric Rossman (edrossma@us.ibm.com) | |
8 | * Cornelia Huck <cornelia.huck@de.ibm.com> | |
9 | * | |
10 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | |
11 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | |
12 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | |
13 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | |
e28d2af4 IT |
14 | */ |
15 | ||
16 | #include <linux/module.h> | |
17 | #include <linux/init.h> | |
18 | #include <linux/interrupt.h> | |
19 | #include <linux/miscdevice.h> | |
20 | #include <linux/fs.h> | |
21 | #include <linux/proc_fs.h> | |
22 | #include <linux/seq_file.h> | |
23 | #include <linux/compat.h> | |
24 | #include <linux/slab.h> | |
25 | #include <linux/atomic.h> | |
26 | #include <linux/uaccess.h> | |
27 | #include <linux/hw_random.h> | |
28 | #include <linux/debugfs.h> | |
29 | #include <asm/debug.h> | |
30 | ||
31 | #include "zcrypt_debug.h" | |
32 | #include "zcrypt_api.h" | |
33 | ||
34 | #include "zcrypt_msgtype6.h" | |
35 | #include "zcrypt_msgtype50.h" | |
36 | ||
37 | /* | |
38 | * Device attributes common for all crypto queue devices. | |
39 | */ | |
40 | ||
41 | static ssize_t zcrypt_queue_online_show(struct device *dev, | |
42 | struct device_attribute *attr, | |
43 | char *buf) | |
44 | { | |
45 | struct zcrypt_queue *zq = to_ap_queue(dev)->private; | |
46 | ||
47 | return snprintf(buf, PAGE_SIZE, "%d\n", zq->online); | |
48 | } | |
49 | ||
50 | static ssize_t zcrypt_queue_online_store(struct device *dev, | |
51 | struct device_attribute *attr, | |
52 | const char *buf, size_t count) | |
53 | { | |
54 | struct zcrypt_queue *zq = to_ap_queue(dev)->private; | |
55 | struct zcrypt_card *zc = zq->zcard; | |
56 | int online; | |
57 | ||
58 | if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) | |
59 | return -EINVAL; | |
60 | ||
61 | if (online && !zc->online) | |
62 | return -EINVAL; | |
63 | zq->online = online; | |
cccd85bf HF |
64 | |
65 | ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x online=%d\n", | |
66 | AP_QID_CARD(zq->queue->qid), | |
67 | AP_QID_QUEUE(zq->queue->qid), | |
68 | online); | |
69 | ||
e28d2af4 IT |
70 | if (!online) |
71 | ap_flush_queue(zq->queue); | |
72 | return count; | |
73 | } | |
74 | ||
75 | static DEVICE_ATTR(online, 0644, zcrypt_queue_online_show, | |
76 | zcrypt_queue_online_store); | |
77 | ||
78 | static struct attribute *zcrypt_queue_attrs[] = { | |
79 | &dev_attr_online.attr, | |
80 | NULL, | |
81 | }; | |
82 | ||
9920decd | 83 | static const struct attribute_group zcrypt_queue_attr_group = { |
e28d2af4 IT |
84 | .attrs = zcrypt_queue_attrs, |
85 | }; | |
86 | ||
87 | void zcrypt_queue_force_online(struct zcrypt_queue *zq, int online) | |
88 | { | |
89 | zq->online = online; | |
90 | if (!online) | |
91 | ap_flush_queue(zq->queue); | |
92 | } | |
93 | ||
94 | struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size) | |
95 | { | |
96 | struct zcrypt_queue *zq; | |
97 | ||
98 | zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL); | |
99 | if (!zq) | |
100 | return NULL; | |
101 | zq->reply.message = kmalloc(max_response_size, GFP_KERNEL); | |
102 | if (!zq->reply.message) | |
103 | goto out_free; | |
104 | zq->reply.length = max_response_size; | |
105 | INIT_LIST_HEAD(&zq->list); | |
e28d2af4 IT |
106 | kref_init(&zq->refcount); |
107 | return zq; | |
108 | ||
109 | out_free: | |
110 | kfree(zq); | |
111 | return NULL; | |
112 | } | |
113 | EXPORT_SYMBOL(zcrypt_queue_alloc); | |
114 | ||
115 | void zcrypt_queue_free(struct zcrypt_queue *zq) | |
116 | { | |
117 | kfree(zq->reply.message); | |
118 | kfree(zq); | |
119 | } | |
120 | EXPORT_SYMBOL(zcrypt_queue_free); | |
121 | ||
122 | static void zcrypt_queue_release(struct kref *kref) | |
123 | { | |
124 | struct zcrypt_queue *zq = | |
125 | container_of(kref, struct zcrypt_queue, refcount); | |
126 | zcrypt_queue_free(zq); | |
127 | } | |
128 | ||
129 | void zcrypt_queue_get(struct zcrypt_queue *zq) | |
130 | { | |
131 | kref_get(&zq->refcount); | |
132 | } | |
133 | EXPORT_SYMBOL(zcrypt_queue_get); | |
134 | ||
135 | int zcrypt_queue_put(struct zcrypt_queue *zq) | |
136 | { | |
137 | return kref_put(&zq->refcount, zcrypt_queue_release); | |
138 | } | |
139 | EXPORT_SYMBOL(zcrypt_queue_put); | |
140 | ||
141 | /** | |
142 | * zcrypt_queue_register() - Register a crypto queue device. | |
143 | * @zq: Pointer to a crypto queue device | |
144 | * | |
145 | * Register a crypto queue device. Returns 0 if successful. | |
146 | */ | |
147 | int zcrypt_queue_register(struct zcrypt_queue *zq) | |
148 | { | |
149 | struct zcrypt_card *zc; | |
150 | int rc; | |
151 | ||
152 | spin_lock(&zcrypt_list_lock); | |
153 | zc = zq->queue->card->private; | |
154 | zcrypt_card_get(zc); | |
155 | zq->zcard = zc; | |
156 | zq->online = 1; /* New devices are online by default. */ | |
cccd85bf HF |
157 | |
158 | ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x register online=1\n", | |
159 | AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); | |
160 | ||
e28d2af4 IT |
161 | list_add_tail(&zq->list, &zc->zqueues); |
162 | zcrypt_device_count++; | |
163 | spin_unlock(&zcrypt_list_lock); | |
164 | ||
165 | rc = sysfs_create_group(&zq->queue->ap_dev.device.kobj, | |
166 | &zcrypt_queue_attr_group); | |
167 | if (rc) | |
168 | goto out; | |
169 | get_device(&zq->queue->ap_dev.device); | |
170 | ||
171 | if (zq->ops->rng) { | |
172 | rc = zcrypt_rng_device_add(); | |
173 | if (rc) | |
174 | goto out_unregister; | |
175 | } | |
176 | return 0; | |
177 | ||
178 | out_unregister: | |
179 | sysfs_remove_group(&zq->queue->ap_dev.device.kobj, | |
180 | &zcrypt_queue_attr_group); | |
181 | put_device(&zq->queue->ap_dev.device); | |
182 | out: | |
183 | spin_lock(&zcrypt_list_lock); | |
184 | list_del_init(&zq->list); | |
185 | spin_unlock(&zcrypt_list_lock); | |
186 | zcrypt_card_put(zc); | |
187 | return rc; | |
188 | } | |
189 | EXPORT_SYMBOL(zcrypt_queue_register); | |
190 | ||
191 | /** | |
192 | * zcrypt_queue_unregister(): Unregister a crypto queue device. | |
193 | * @zq: Pointer to crypto queue device | |
194 | * | |
195 | * Unregister a crypto queue device. | |
196 | */ | |
197 | void zcrypt_queue_unregister(struct zcrypt_queue *zq) | |
198 | { | |
199 | struct zcrypt_card *zc; | |
200 | ||
cccd85bf HF |
201 | ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x unregister\n", |
202 | AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); | |
203 | ||
e28d2af4 IT |
204 | zc = zq->zcard; |
205 | spin_lock(&zcrypt_list_lock); | |
206 | list_del_init(&zq->list); | |
207 | zcrypt_device_count--; | |
208 | spin_unlock(&zcrypt_list_lock); | |
209 | zcrypt_card_put(zc); | |
210 | if (zq->ops->rng) | |
211 | zcrypt_rng_device_remove(); | |
212 | sysfs_remove_group(&zq->queue->ap_dev.device.kobj, | |
213 | &zcrypt_queue_attr_group); | |
214 | put_device(&zq->queue->ap_dev.device); | |
215 | zcrypt_queue_put(zq); | |
216 | } | |
217 | EXPORT_SYMBOL(zcrypt_queue_unregister); |