1dbaf0624SGonglei /* Management for virtio crypto devices (refer to adf_dev_mgr.c) 2dbaf0624SGonglei * 3dbaf0624SGonglei * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. 4dbaf0624SGonglei * 5dbaf0624SGonglei * This program is free software; you can redistribute it and/or modify 6dbaf0624SGonglei * it under the terms of the GNU General Public License as published by 7dbaf0624SGonglei * the Free Software Foundation; either version 2 of the License, or 8dbaf0624SGonglei * (at your option) any later version. 9dbaf0624SGonglei * 10dbaf0624SGonglei * This program is distributed in the hope that it will be useful, 11dbaf0624SGonglei * but WITHOUT ANY WARRANTY; without even the implied warranty of 12dbaf0624SGonglei * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13dbaf0624SGonglei * GNU General Public License for more details. 14dbaf0624SGonglei * 15dbaf0624SGonglei * You should have received a copy of the GNU General Public License 16dbaf0624SGonglei * along with this program; if not, see <http://www.gnu.org/licenses/>. 17dbaf0624SGonglei */ 18dbaf0624SGonglei 19dbaf0624SGonglei #include <linux/mutex.h> 20dbaf0624SGonglei #include <linux/list.h> 21dbaf0624SGonglei #include <linux/module.h> 22dbaf0624SGonglei 23dbaf0624SGonglei #include <uapi/linux/virtio_crypto.h> 24dbaf0624SGonglei #include "virtio_crypto_common.h" 25dbaf0624SGonglei 26dbaf0624SGonglei static LIST_HEAD(virtio_crypto_table); 27dbaf0624SGonglei static uint32_t num_devices; 28dbaf0624SGonglei 29dbaf0624SGonglei /* The table_lock protects the above global list and num_devices */ 30dbaf0624SGonglei static DEFINE_MUTEX(table_lock); 31dbaf0624SGonglei 32dbaf0624SGonglei #define VIRTIO_CRYPTO_MAX_DEVICES 32 33dbaf0624SGonglei 34dbaf0624SGonglei 35dbaf0624SGonglei /* 36dbaf0624SGonglei * virtcrypto_devmgr_add_dev() - Add vcrypto_dev to the acceleration 37dbaf0624SGonglei * framework. 38dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 39dbaf0624SGonglei * 40dbaf0624SGonglei * Function adds virtio crypto device to the global list. 41dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 42dbaf0624SGonglei * 43dbaf0624SGonglei * Return: 0 on success, error code othewise. 44dbaf0624SGonglei */ 45dbaf0624SGonglei int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev) 46dbaf0624SGonglei { 47dbaf0624SGonglei struct list_head *itr; 48dbaf0624SGonglei 49dbaf0624SGonglei mutex_lock(&table_lock); 50dbaf0624SGonglei if (num_devices == VIRTIO_CRYPTO_MAX_DEVICES) { 51dbaf0624SGonglei pr_info("virtio_crypto: only support up to %d devices\n", 52dbaf0624SGonglei VIRTIO_CRYPTO_MAX_DEVICES); 53dbaf0624SGonglei mutex_unlock(&table_lock); 54dbaf0624SGonglei return -EFAULT; 55dbaf0624SGonglei } 56dbaf0624SGonglei 57dbaf0624SGonglei list_for_each(itr, &virtio_crypto_table) { 58dbaf0624SGonglei struct virtio_crypto *ptr = 59dbaf0624SGonglei list_entry(itr, struct virtio_crypto, list); 60dbaf0624SGonglei 61dbaf0624SGonglei if (ptr == vcrypto_dev) { 62dbaf0624SGonglei mutex_unlock(&table_lock); 63dbaf0624SGonglei return -EEXIST; 64dbaf0624SGonglei } 65dbaf0624SGonglei } 66dbaf0624SGonglei atomic_set(&vcrypto_dev->ref_count, 0); 67dbaf0624SGonglei list_add_tail(&vcrypto_dev->list, &virtio_crypto_table); 68dbaf0624SGonglei vcrypto_dev->dev_id = num_devices++; 69dbaf0624SGonglei mutex_unlock(&table_lock); 70dbaf0624SGonglei return 0; 71dbaf0624SGonglei } 72dbaf0624SGonglei 73dbaf0624SGonglei struct list_head *virtcrypto_devmgr_get_head(void) 74dbaf0624SGonglei { 75dbaf0624SGonglei return &virtio_crypto_table; 76dbaf0624SGonglei } 77dbaf0624SGonglei 78dbaf0624SGonglei /* 79dbaf0624SGonglei * virtcrypto_devmgr_rm_dev() - Remove vcrypto_dev from the acceleration 80dbaf0624SGonglei * framework. 81dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 82dbaf0624SGonglei * 83dbaf0624SGonglei * Function removes virtio crypto device from the acceleration framework. 84dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 85dbaf0624SGonglei * 86dbaf0624SGonglei * Return: void 87dbaf0624SGonglei */ 88dbaf0624SGonglei void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev) 89dbaf0624SGonglei { 90dbaf0624SGonglei mutex_lock(&table_lock); 91dbaf0624SGonglei list_del(&vcrypto_dev->list); 92dbaf0624SGonglei num_devices--; 93dbaf0624SGonglei mutex_unlock(&table_lock); 94dbaf0624SGonglei } 95dbaf0624SGonglei 96dbaf0624SGonglei /* 97dbaf0624SGonglei * virtcrypto_devmgr_get_first() 98dbaf0624SGonglei * 99dbaf0624SGonglei * Function returns the first virtio crypto device from the acceleration 100dbaf0624SGonglei * framework. 101dbaf0624SGonglei * 102dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 103dbaf0624SGonglei * 104dbaf0624SGonglei * Return: pointer to vcrypto_dev or NULL if not found. 105dbaf0624SGonglei */ 106dbaf0624SGonglei struct virtio_crypto *virtcrypto_devmgr_get_first(void) 107dbaf0624SGonglei { 108dbaf0624SGonglei struct virtio_crypto *dev = NULL; 109dbaf0624SGonglei 110dbaf0624SGonglei mutex_lock(&table_lock); 111dbaf0624SGonglei if (!list_empty(&virtio_crypto_table)) 112dbaf0624SGonglei dev = list_first_entry(&virtio_crypto_table, 113dbaf0624SGonglei struct virtio_crypto, 114dbaf0624SGonglei list); 115dbaf0624SGonglei mutex_unlock(&table_lock); 116dbaf0624SGonglei return dev; 117dbaf0624SGonglei } 118dbaf0624SGonglei 119dbaf0624SGonglei /* 120dbaf0624SGonglei * virtcrypto_dev_in_use() - Check whether vcrypto_dev is currently in use 121dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 122dbaf0624SGonglei * 123dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 124dbaf0624SGonglei * 125dbaf0624SGonglei * Return: 1 when device is in use, 0 otherwise. 126dbaf0624SGonglei */ 127dbaf0624SGonglei int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev) 128dbaf0624SGonglei { 129dbaf0624SGonglei return atomic_read(&vcrypto_dev->ref_count) != 0; 130dbaf0624SGonglei } 131dbaf0624SGonglei 132dbaf0624SGonglei /* 133dbaf0624SGonglei * virtcrypto_dev_get() - Increment vcrypto_dev reference count 134dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 135dbaf0624SGonglei * 136dbaf0624SGonglei * Increment the vcrypto_dev refcount and if this is the first time 137dbaf0624SGonglei * incrementing it during this period the vcrypto_dev is in use, 138dbaf0624SGonglei * increment the module refcount too. 139dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 140dbaf0624SGonglei * 141dbaf0624SGonglei * Return: 0 when successful, EFAULT when fail to bump module refcount 142dbaf0624SGonglei */ 143dbaf0624SGonglei int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev) 144dbaf0624SGonglei { 145dbaf0624SGonglei if (atomic_add_return(1, &vcrypto_dev->ref_count) == 1) 146dbaf0624SGonglei if (!try_module_get(vcrypto_dev->owner)) 147dbaf0624SGonglei return -EFAULT; 148dbaf0624SGonglei return 0; 149dbaf0624SGonglei } 150dbaf0624SGonglei 151dbaf0624SGonglei /* 152dbaf0624SGonglei * virtcrypto_dev_put() - Decrement vcrypto_dev reference count 153dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 154dbaf0624SGonglei * 155dbaf0624SGonglei * Decrement the vcrypto_dev refcount and if this is the last time 156dbaf0624SGonglei * decrementing it during this period the vcrypto_dev is in use, 157dbaf0624SGonglei * decrement the module refcount too. 158dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 159dbaf0624SGonglei * 160dbaf0624SGonglei * Return: void 161dbaf0624SGonglei */ 162dbaf0624SGonglei void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev) 163dbaf0624SGonglei { 164dbaf0624SGonglei if (atomic_sub_return(1, &vcrypto_dev->ref_count) == 0) 165dbaf0624SGonglei module_put(vcrypto_dev->owner); 166dbaf0624SGonglei } 167dbaf0624SGonglei 168dbaf0624SGonglei /* 169dbaf0624SGonglei * virtcrypto_dev_started() - Check whether device has started 170dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 171dbaf0624SGonglei * 172dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 173dbaf0624SGonglei * 174dbaf0624SGonglei * Return: 1 when the device has started, 0 otherwise 175dbaf0624SGonglei */ 176dbaf0624SGonglei int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev) 177dbaf0624SGonglei { 178dbaf0624SGonglei return (vcrypto_dev->status & VIRTIO_CRYPTO_S_HW_READY); 179dbaf0624SGonglei } 180dbaf0624SGonglei 181dbaf0624SGonglei /* 182dbaf0624SGonglei * virtcrypto_get_dev_node() - Get vcrypto_dev on the node. 183dbaf0624SGonglei * @node: Node id the driver works. 184dbaf0624SGonglei * 185dbaf0624SGonglei * Function returns the virtio crypto device used fewest on the node. 186dbaf0624SGonglei * 187dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 188dbaf0624SGonglei * 189dbaf0624SGonglei * Return: pointer to vcrypto_dev or NULL if not found. 190dbaf0624SGonglei */ 191dbaf0624SGonglei struct virtio_crypto *virtcrypto_get_dev_node(int node) 192dbaf0624SGonglei { 193dbaf0624SGonglei struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev; 194dbaf0624SGonglei unsigned long best = ~0; 195dbaf0624SGonglei unsigned long ctr; 196dbaf0624SGonglei 197dbaf0624SGonglei mutex_lock(&table_lock); 198dbaf0624SGonglei list_for_each_entry(tmp_dev, virtcrypto_devmgr_get_head(), list) { 199dbaf0624SGonglei 200dbaf0624SGonglei if ((node == dev_to_node(&tmp_dev->vdev->dev) || 201dbaf0624SGonglei dev_to_node(&tmp_dev->vdev->dev) < 0) && 202dbaf0624SGonglei virtcrypto_dev_started(tmp_dev)) { 203dbaf0624SGonglei ctr = atomic_read(&tmp_dev->ref_count); 204dbaf0624SGonglei if (best > ctr) { 205dbaf0624SGonglei vcrypto_dev = tmp_dev; 206dbaf0624SGonglei best = ctr; 207dbaf0624SGonglei } 208dbaf0624SGonglei } 209dbaf0624SGonglei } 210dbaf0624SGonglei 211dbaf0624SGonglei if (!vcrypto_dev) { 212dbaf0624SGonglei pr_info("virtio_crypto: Could not find a device on node %d\n", 213dbaf0624SGonglei node); 214dbaf0624SGonglei /* Get any started device */ 215dbaf0624SGonglei list_for_each_entry(tmp_dev, 216dbaf0624SGonglei virtcrypto_devmgr_get_head(), list) { 217dbaf0624SGonglei if (virtcrypto_dev_started(tmp_dev)) { 218dbaf0624SGonglei vcrypto_dev = tmp_dev; 219dbaf0624SGonglei break; 220dbaf0624SGonglei } 221dbaf0624SGonglei } 222dbaf0624SGonglei } 223dbaf0624SGonglei mutex_unlock(&table_lock); 224dbaf0624SGonglei if (!vcrypto_dev) 225dbaf0624SGonglei return NULL; 226dbaf0624SGonglei 227dbaf0624SGonglei virtcrypto_dev_get(vcrypto_dev); 228dbaf0624SGonglei return vcrypto_dev; 229dbaf0624SGonglei } 230dbaf0624SGonglei 231dbaf0624SGonglei /* 232dbaf0624SGonglei * virtcrypto_dev_start() - Start virtio crypto device 233dbaf0624SGonglei * @vcrypto: Pointer to virtio crypto device. 234dbaf0624SGonglei * 235dbaf0624SGonglei * Function notifies all the registered services that the virtio crypto device 236dbaf0624SGonglei * is ready to be used. 237dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 238dbaf0624SGonglei * 239dbaf0624SGonglei * Return: 0 on success, EFAULT when fail to register algorithms 240dbaf0624SGonglei */ 241dbaf0624SGonglei int virtcrypto_dev_start(struct virtio_crypto *vcrypto) 242dbaf0624SGonglei { 243dbaf0624SGonglei if (virtio_crypto_algs_register()) { 244dbaf0624SGonglei pr_err("virtio_crypto: Failed to register crypto algs\n"); 245dbaf0624SGonglei return -EFAULT; 246dbaf0624SGonglei } 247dbaf0624SGonglei 248dbaf0624SGonglei return 0; 249dbaf0624SGonglei } 250dbaf0624SGonglei 251dbaf0624SGonglei /* 252dbaf0624SGonglei * virtcrypto_dev_stop() - Stop virtio crypto device 253dbaf0624SGonglei * @vcrypto: Pointer to virtio crypto device. 254dbaf0624SGonglei * 255dbaf0624SGonglei * Function notifies all the registered services that the virtio crypto device 256dbaf0624SGonglei * is ready to be used. 257dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 258dbaf0624SGonglei * 259dbaf0624SGonglei * Return: void 260dbaf0624SGonglei */ 261dbaf0624SGonglei void virtcrypto_dev_stop(struct virtio_crypto *vcrypto) 262dbaf0624SGonglei { 263dbaf0624SGonglei virtio_crypto_algs_unregister(); 264dbaf0624SGonglei } 265