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