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