18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2001, 2012 48c2ecf20Sopenharmony_ci * Author(s): Robert Burroughs 58c2ecf20Sopenharmony_ci * Eric Rossman (edrossma@us.ibm.com) 68c2ecf20Sopenharmony_ci * Cornelia Huck <cornelia.huck@de.ibm.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) 98c2ecf20Sopenharmony_ci * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> 108c2ecf20Sopenharmony_ci * Ralph Wuerthner <rwuerthn@de.ibm.com> 118c2ecf20Sopenharmony_ci * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/fs.h> 198c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 208c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 218c2ecf20Sopenharmony_ci#include <linux/compat.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/atomic.h> 248c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 258c2ecf20Sopenharmony_ci#include <linux/hw_random.h> 268c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 278c2ecf20Sopenharmony_ci#include <asm/debug.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "zcrypt_debug.h" 308c2ecf20Sopenharmony_ci#include "zcrypt_api.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "zcrypt_msgtype6.h" 338c2ecf20Sopenharmony_ci#include "zcrypt_msgtype50.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Device attributes common for all crypto queue devices. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic ssize_t online_show(struct device *dev, 408c2ecf20Sopenharmony_ci struct device_attribute *attr, 418c2ecf20Sopenharmony_ci char *buf) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 448c2ecf20Sopenharmony_ci struct zcrypt_queue *zq = aq->private; 458c2ecf20Sopenharmony_ci int online = aq->config && zq->online ? 1 : 0; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", online); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic ssize_t online_store(struct device *dev, 518c2ecf20Sopenharmony_ci struct device_attribute *attr, 528c2ecf20Sopenharmony_ci const char *buf, size_t count) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 558c2ecf20Sopenharmony_ci struct zcrypt_queue *zq = aq->private; 568c2ecf20Sopenharmony_ci struct zcrypt_card *zc = zq->zcard; 578c2ecf20Sopenharmony_ci int online; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) 608c2ecf20Sopenharmony_ci return -EINVAL; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (online && (!aq->config || !aq->card->config)) 638c2ecf20Sopenharmony_ci return -ENODEV; 648c2ecf20Sopenharmony_ci if (online && !zc->online) 658c2ecf20Sopenharmony_ci return -EINVAL; 668c2ecf20Sopenharmony_ci zq->online = online; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x online=%d\n", 698c2ecf20Sopenharmony_ci AP_QID_CARD(zq->queue->qid), 708c2ecf20Sopenharmony_ci AP_QID_QUEUE(zq->queue->qid), 718c2ecf20Sopenharmony_ci online); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (!online) 748c2ecf20Sopenharmony_ci ap_flush_queue(zq->queue); 758c2ecf20Sopenharmony_ci return count; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(online); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic ssize_t load_show(struct device *dev, 818c2ecf20Sopenharmony_ci struct device_attribute *attr, 828c2ecf20Sopenharmony_ci char *buf) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct zcrypt_queue *zq = to_ap_queue(dev)->private; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(load); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct attribute *zcrypt_queue_attrs[] = { 928c2ecf20Sopenharmony_ci &dev_attr_online.attr, 938c2ecf20Sopenharmony_ci &dev_attr_load.attr, 948c2ecf20Sopenharmony_ci NULL, 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const struct attribute_group zcrypt_queue_attr_group = { 988c2ecf20Sopenharmony_ci .attrs = zcrypt_queue_attrs, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid zcrypt_queue_force_online(struct zcrypt_queue *zq, int online) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci zq->online = online; 1048c2ecf20Sopenharmony_ci if (!online) 1058c2ecf20Sopenharmony_ci ap_flush_queue(zq->queue); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistruct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL); 1138c2ecf20Sopenharmony_ci if (!zq) 1148c2ecf20Sopenharmony_ci return NULL; 1158c2ecf20Sopenharmony_ci zq->reply.msg = kmalloc(max_response_size, GFP_KERNEL); 1168c2ecf20Sopenharmony_ci if (!zq->reply.msg) 1178c2ecf20Sopenharmony_ci goto out_free; 1188c2ecf20Sopenharmony_ci zq->reply.len = max_response_size; 1198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&zq->list); 1208c2ecf20Sopenharmony_ci kref_init(&zq->refcount); 1218c2ecf20Sopenharmony_ci return zq; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciout_free: 1248c2ecf20Sopenharmony_ci kfree(zq); 1258c2ecf20Sopenharmony_ci return NULL; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_queue_alloc); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_civoid zcrypt_queue_free(struct zcrypt_queue *zq) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci kfree(zq->reply.msg); 1328c2ecf20Sopenharmony_ci kfree(zq); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_queue_free); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void zcrypt_queue_release(struct kref *kref) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct zcrypt_queue *zq = 1398c2ecf20Sopenharmony_ci container_of(kref, struct zcrypt_queue, refcount); 1408c2ecf20Sopenharmony_ci zcrypt_queue_free(zq); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_civoid zcrypt_queue_get(struct zcrypt_queue *zq) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci kref_get(&zq->refcount); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_queue_get); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciint zcrypt_queue_put(struct zcrypt_queue *zq) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci return kref_put(&zq->refcount, zcrypt_queue_release); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_queue_put); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/** 1568c2ecf20Sopenharmony_ci * zcrypt_queue_register() - Register a crypto queue device. 1578c2ecf20Sopenharmony_ci * @zq: Pointer to a crypto queue device 1588c2ecf20Sopenharmony_ci * 1598c2ecf20Sopenharmony_ci * Register a crypto queue device. Returns 0 if successful. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ciint zcrypt_queue_register(struct zcrypt_queue *zq) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 1648c2ecf20Sopenharmony_ci int rc; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 1678c2ecf20Sopenharmony_ci zc = zq->queue->card->private; 1688c2ecf20Sopenharmony_ci zcrypt_card_get(zc); 1698c2ecf20Sopenharmony_ci zq->zcard = zc; 1708c2ecf20Sopenharmony_ci zq->online = 1; /* New devices are online by default. */ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x register online=1\n", 1738c2ecf20Sopenharmony_ci AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci list_add_tail(&zq->list, &zc->zqueues); 1768c2ecf20Sopenharmony_ci zcrypt_device_count++; 1778c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci rc = sysfs_create_group(&zq->queue->ap_dev.device.kobj, 1808c2ecf20Sopenharmony_ci &zcrypt_queue_attr_group); 1818c2ecf20Sopenharmony_ci if (rc) 1828c2ecf20Sopenharmony_ci goto out; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (zq->ops->rng) { 1858c2ecf20Sopenharmony_ci rc = zcrypt_rng_device_add(); 1868c2ecf20Sopenharmony_ci if (rc) 1878c2ecf20Sopenharmony_ci goto out_unregister; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciout_unregister: 1928c2ecf20Sopenharmony_ci sysfs_remove_group(&zq->queue->ap_dev.device.kobj, 1938c2ecf20Sopenharmony_ci &zcrypt_queue_attr_group); 1948c2ecf20Sopenharmony_ciout: 1958c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 1968c2ecf20Sopenharmony_ci list_del_init(&zq->list); 1978c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 1988c2ecf20Sopenharmony_ci zcrypt_card_put(zc); 1998c2ecf20Sopenharmony_ci return rc; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_queue_register); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * zcrypt_queue_unregister(): Unregister a crypto queue device. 2058c2ecf20Sopenharmony_ci * @zq: Pointer to crypto queue device 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Unregister a crypto queue device. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_civoid zcrypt_queue_unregister(struct zcrypt_queue *zq) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x unregister\n", 2148c2ecf20Sopenharmony_ci AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci zc = zq->zcard; 2178c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 2188c2ecf20Sopenharmony_ci list_del_init(&zq->list); 2198c2ecf20Sopenharmony_ci zcrypt_device_count--; 2208c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 2218c2ecf20Sopenharmony_ci if (zq->ops->rng) 2228c2ecf20Sopenharmony_ci zcrypt_rng_device_remove(); 2238c2ecf20Sopenharmony_ci sysfs_remove_group(&zq->queue->ap_dev.device.kobj, 2248c2ecf20Sopenharmony_ci &zcrypt_queue_attr_group); 2258c2ecf20Sopenharmony_ci zcrypt_card_put(zc); 2268c2ecf20Sopenharmony_ci zcrypt_queue_put(zq); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_queue_unregister); 229