11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2dbaf0624SGonglei /* Management for virtio crypto devices (refer to adf_dev_mgr.c) 3dbaf0624SGonglei * 4dbaf0624SGonglei * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. 5dbaf0624SGonglei */ 6dbaf0624SGonglei 7dbaf0624SGonglei #include <linux/mutex.h> 8dbaf0624SGonglei #include <linux/list.h> 9dbaf0624SGonglei #include <linux/module.h> 10dbaf0624SGonglei 11dbaf0624SGonglei #include <uapi/linux/virtio_crypto.h> 12dbaf0624SGonglei #include "virtio_crypto_common.h" 13dbaf0624SGonglei 14dbaf0624SGonglei static LIST_HEAD(virtio_crypto_table); 15dbaf0624SGonglei static uint32_t num_devices; 16dbaf0624SGonglei 17dbaf0624SGonglei /* The table_lock protects the above global list and num_devices */ 18dbaf0624SGonglei static DEFINE_MUTEX(table_lock); 19dbaf0624SGonglei 20dbaf0624SGonglei #define VIRTIO_CRYPTO_MAX_DEVICES 32 21dbaf0624SGonglei 22dbaf0624SGonglei 23dbaf0624SGonglei /* 24dbaf0624SGonglei * virtcrypto_devmgr_add_dev() - Add vcrypto_dev to the acceleration 25dbaf0624SGonglei * framework. 26dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 27dbaf0624SGonglei * 28dbaf0624SGonglei * Function adds virtio crypto device to the global list. 29dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 30dbaf0624SGonglei * 31dbaf0624SGonglei * Return: 0 on success, error code othewise. 32dbaf0624SGonglei */ 33dbaf0624SGonglei int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev) 34dbaf0624SGonglei { 35dbaf0624SGonglei struct list_head *itr; 36dbaf0624SGonglei 37dbaf0624SGonglei mutex_lock(&table_lock); 38dbaf0624SGonglei if (num_devices == VIRTIO_CRYPTO_MAX_DEVICES) { 39dbaf0624SGonglei pr_info("virtio_crypto: only support up to %d devices\n", 40dbaf0624SGonglei VIRTIO_CRYPTO_MAX_DEVICES); 41dbaf0624SGonglei mutex_unlock(&table_lock); 42dbaf0624SGonglei return -EFAULT; 43dbaf0624SGonglei } 44dbaf0624SGonglei 45dbaf0624SGonglei list_for_each(itr, &virtio_crypto_table) { 46dbaf0624SGonglei struct virtio_crypto *ptr = 47dbaf0624SGonglei list_entry(itr, struct virtio_crypto, list); 48dbaf0624SGonglei 49dbaf0624SGonglei if (ptr == vcrypto_dev) { 50dbaf0624SGonglei mutex_unlock(&table_lock); 51dbaf0624SGonglei return -EEXIST; 52dbaf0624SGonglei } 53dbaf0624SGonglei } 54dbaf0624SGonglei atomic_set(&vcrypto_dev->ref_count, 0); 55dbaf0624SGonglei list_add_tail(&vcrypto_dev->list, &virtio_crypto_table); 56dbaf0624SGonglei vcrypto_dev->dev_id = num_devices++; 57dbaf0624SGonglei mutex_unlock(&table_lock); 58dbaf0624SGonglei return 0; 59dbaf0624SGonglei } 60dbaf0624SGonglei 61dbaf0624SGonglei struct list_head *virtcrypto_devmgr_get_head(void) 62dbaf0624SGonglei { 63dbaf0624SGonglei return &virtio_crypto_table; 64dbaf0624SGonglei } 65dbaf0624SGonglei 66dbaf0624SGonglei /* 67dbaf0624SGonglei * virtcrypto_devmgr_rm_dev() - Remove vcrypto_dev from the acceleration 68dbaf0624SGonglei * framework. 69dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 70dbaf0624SGonglei * 71dbaf0624SGonglei * Function removes virtio crypto device from the acceleration framework. 72dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 73dbaf0624SGonglei * 74dbaf0624SGonglei * Return: void 75dbaf0624SGonglei */ 76dbaf0624SGonglei void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev) 77dbaf0624SGonglei { 78dbaf0624SGonglei mutex_lock(&table_lock); 79dbaf0624SGonglei list_del(&vcrypto_dev->list); 80dbaf0624SGonglei num_devices--; 81dbaf0624SGonglei mutex_unlock(&table_lock); 82dbaf0624SGonglei } 83dbaf0624SGonglei 84dbaf0624SGonglei /* 85dbaf0624SGonglei * virtcrypto_devmgr_get_first() 86dbaf0624SGonglei * 87dbaf0624SGonglei * Function returns the first virtio crypto device from the acceleration 88dbaf0624SGonglei * framework. 89dbaf0624SGonglei * 90dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 91dbaf0624SGonglei * 92dbaf0624SGonglei * Return: pointer to vcrypto_dev or NULL if not found. 93dbaf0624SGonglei */ 94dbaf0624SGonglei struct virtio_crypto *virtcrypto_devmgr_get_first(void) 95dbaf0624SGonglei { 96dbaf0624SGonglei struct virtio_crypto *dev = NULL; 97dbaf0624SGonglei 98dbaf0624SGonglei mutex_lock(&table_lock); 99dbaf0624SGonglei if (!list_empty(&virtio_crypto_table)) 100dbaf0624SGonglei dev = list_first_entry(&virtio_crypto_table, 101dbaf0624SGonglei struct virtio_crypto, 102dbaf0624SGonglei list); 103dbaf0624SGonglei mutex_unlock(&table_lock); 104dbaf0624SGonglei return dev; 105dbaf0624SGonglei } 106dbaf0624SGonglei 107dbaf0624SGonglei /* 108dbaf0624SGonglei * virtcrypto_dev_in_use() - Check whether vcrypto_dev is currently in use 109dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 110dbaf0624SGonglei * 111dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 112dbaf0624SGonglei * 113dbaf0624SGonglei * Return: 1 when device is in use, 0 otherwise. 114dbaf0624SGonglei */ 115dbaf0624SGonglei int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev) 116dbaf0624SGonglei { 117dbaf0624SGonglei return atomic_read(&vcrypto_dev->ref_count) != 0; 118dbaf0624SGonglei } 119dbaf0624SGonglei 120dbaf0624SGonglei /* 121dbaf0624SGonglei * virtcrypto_dev_get() - Increment vcrypto_dev reference count 122dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 123dbaf0624SGonglei * 124dbaf0624SGonglei * Increment the vcrypto_dev refcount and if this is the first time 125dbaf0624SGonglei * incrementing it during this period the vcrypto_dev is in use, 126dbaf0624SGonglei * increment the module refcount too. 127dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 128dbaf0624SGonglei * 129dbaf0624SGonglei * Return: 0 when successful, EFAULT when fail to bump module refcount 130dbaf0624SGonglei */ 131dbaf0624SGonglei int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev) 132dbaf0624SGonglei { 133dbaf0624SGonglei if (atomic_add_return(1, &vcrypto_dev->ref_count) == 1) 134dbaf0624SGonglei if (!try_module_get(vcrypto_dev->owner)) 135dbaf0624SGonglei return -EFAULT; 136dbaf0624SGonglei return 0; 137dbaf0624SGonglei } 138dbaf0624SGonglei 139dbaf0624SGonglei /* 140dbaf0624SGonglei * virtcrypto_dev_put() - Decrement vcrypto_dev reference count 141dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 142dbaf0624SGonglei * 143dbaf0624SGonglei * Decrement the vcrypto_dev refcount and if this is the last time 144dbaf0624SGonglei * decrementing it during this period the vcrypto_dev is in use, 145dbaf0624SGonglei * decrement the module refcount too. 146dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 147dbaf0624SGonglei * 148dbaf0624SGonglei * Return: void 149dbaf0624SGonglei */ 150dbaf0624SGonglei void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev) 151dbaf0624SGonglei { 152dbaf0624SGonglei if (atomic_sub_return(1, &vcrypto_dev->ref_count) == 0) 153dbaf0624SGonglei module_put(vcrypto_dev->owner); 154dbaf0624SGonglei } 155dbaf0624SGonglei 156dbaf0624SGonglei /* 157dbaf0624SGonglei * virtcrypto_dev_started() - Check whether device has started 158dbaf0624SGonglei * @vcrypto_dev: Pointer to virtio crypto device. 159dbaf0624SGonglei * 160dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 161dbaf0624SGonglei * 162dbaf0624SGonglei * Return: 1 when the device has started, 0 otherwise 163dbaf0624SGonglei */ 164dbaf0624SGonglei int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev) 165dbaf0624SGonglei { 166dbaf0624SGonglei return (vcrypto_dev->status & VIRTIO_CRYPTO_S_HW_READY); 167dbaf0624SGonglei } 168dbaf0624SGonglei 169dbaf0624SGonglei /* 170dbaf0624SGonglei * virtcrypto_get_dev_node() - Get vcrypto_dev on the node. 171dbaf0624SGonglei * @node: Node id the driver works. 172d0d859bbSFarhan Ali * @service: Crypto service that needs to be supported by the 173d0d859bbSFarhan Ali * dev 174d0d859bbSFarhan Ali * @algo: The algorithm number that needs to be supported by the 175d0d859bbSFarhan Ali * dev 176dbaf0624SGonglei * 177d0d859bbSFarhan Ali * Function returns the virtio crypto device used fewest on the node, 178d0d859bbSFarhan Ali * and supports the given crypto service and algorithm. 179dbaf0624SGonglei * 180dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 181dbaf0624SGonglei * 182dbaf0624SGonglei * Return: pointer to vcrypto_dev or NULL if not found. 183dbaf0624SGonglei */ 184d0d859bbSFarhan Ali struct virtio_crypto *virtcrypto_get_dev_node(int node, uint32_t service, 185d0d859bbSFarhan Ali uint32_t algo) 186dbaf0624SGonglei { 187dbaf0624SGonglei struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev; 188dbaf0624SGonglei unsigned long best = ~0; 189dbaf0624SGonglei unsigned long ctr; 190dbaf0624SGonglei 191dbaf0624SGonglei mutex_lock(&table_lock); 192dbaf0624SGonglei list_for_each_entry(tmp_dev, virtcrypto_devmgr_get_head(), list) { 193dbaf0624SGonglei 194dbaf0624SGonglei if ((node == dev_to_node(&tmp_dev->vdev->dev) || 195dbaf0624SGonglei dev_to_node(&tmp_dev->vdev->dev) < 0) && 196d0d859bbSFarhan Ali virtcrypto_dev_started(tmp_dev) && 197d0d859bbSFarhan Ali virtcrypto_algo_is_supported(tmp_dev, service, algo)) { 198dbaf0624SGonglei ctr = atomic_read(&tmp_dev->ref_count); 199dbaf0624SGonglei if (best > ctr) { 200dbaf0624SGonglei vcrypto_dev = tmp_dev; 201dbaf0624SGonglei best = ctr; 202dbaf0624SGonglei } 203dbaf0624SGonglei } 204dbaf0624SGonglei } 205dbaf0624SGonglei 206dbaf0624SGonglei if (!vcrypto_dev) { 207dbaf0624SGonglei pr_info("virtio_crypto: Could not find a device on node %d\n", 208dbaf0624SGonglei node); 209dbaf0624SGonglei /* Get any started device */ 210dbaf0624SGonglei list_for_each_entry(tmp_dev, 211dbaf0624SGonglei virtcrypto_devmgr_get_head(), list) { 212d0d859bbSFarhan Ali if (virtcrypto_dev_started(tmp_dev) && 213d0d859bbSFarhan Ali virtcrypto_algo_is_supported(tmp_dev, 214d0d859bbSFarhan Ali service, algo)) { 215dbaf0624SGonglei vcrypto_dev = tmp_dev; 216dbaf0624SGonglei break; 217dbaf0624SGonglei } 218dbaf0624SGonglei } 219dbaf0624SGonglei } 220dbaf0624SGonglei mutex_unlock(&table_lock); 221dbaf0624SGonglei if (!vcrypto_dev) 222dbaf0624SGonglei return NULL; 223dbaf0624SGonglei 224dbaf0624SGonglei virtcrypto_dev_get(vcrypto_dev); 225dbaf0624SGonglei return vcrypto_dev; 226dbaf0624SGonglei } 227dbaf0624SGonglei 228dbaf0624SGonglei /* 229dbaf0624SGonglei * virtcrypto_dev_start() - Start virtio crypto device 230dbaf0624SGonglei * @vcrypto: Pointer to virtio crypto device. 231dbaf0624SGonglei * 232dbaf0624SGonglei * Function notifies all the registered services that the virtio crypto device 233dbaf0624SGonglei * is ready to be used. 234dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 235dbaf0624SGonglei * 236dbaf0624SGonglei * Return: 0 on success, EFAULT when fail to register algorithms 237dbaf0624SGonglei */ 238dbaf0624SGonglei int virtcrypto_dev_start(struct virtio_crypto *vcrypto) 239dbaf0624SGonglei { 240d0d859bbSFarhan Ali if (virtio_crypto_algs_register(vcrypto)) { 241dbaf0624SGonglei pr_err("virtio_crypto: Failed to register crypto algs\n"); 242dbaf0624SGonglei return -EFAULT; 243dbaf0624SGonglei } 244dbaf0624SGonglei 245*59ca6c93Szhenwei pi if (virtio_crypto_akcipher_algs_register(vcrypto)) { 246*59ca6c93Szhenwei pi pr_err("virtio_crypto: Failed to register crypto akcipher algs\n"); 247*59ca6c93Szhenwei pi virtio_crypto_algs_unregister(vcrypto); 248*59ca6c93Szhenwei pi return -EFAULT; 249*59ca6c93Szhenwei pi } 250*59ca6c93Szhenwei pi 251dbaf0624SGonglei return 0; 252dbaf0624SGonglei } 253dbaf0624SGonglei 254dbaf0624SGonglei /* 255dbaf0624SGonglei * virtcrypto_dev_stop() - Stop virtio crypto device 256dbaf0624SGonglei * @vcrypto: Pointer to virtio crypto device. 257dbaf0624SGonglei * 258dbaf0624SGonglei * Function notifies all the registered services that the virtio crypto device 259dbaf0624SGonglei * is ready to be used. 260dbaf0624SGonglei * To be used by virtio crypto device specific drivers. 261dbaf0624SGonglei * 262dbaf0624SGonglei * Return: void 263dbaf0624SGonglei */ 264dbaf0624SGonglei void virtcrypto_dev_stop(struct virtio_crypto *vcrypto) 265dbaf0624SGonglei { 266d0d859bbSFarhan Ali virtio_crypto_algs_unregister(vcrypto); 267*59ca6c93Szhenwei pi virtio_crypto_akcipher_algs_unregister(vcrypto); 268d0d859bbSFarhan Ali } 269d0d859bbSFarhan Ali 270d0d859bbSFarhan Ali /* 271d0d859bbSFarhan Ali * vcrypto_algo_is_supported() 272d0d859bbSFarhan Ali * @vcrypto: Pointer to virtio crypto device. 273d0d859bbSFarhan Ali * @service: The bit number for service validate. 274d0d859bbSFarhan Ali * See VIRTIO_CRYPTO_SERVICE_* 275d0d859bbSFarhan Ali * @algo : The bit number for the algorithm to validate. 276d0d859bbSFarhan Ali * 277d0d859bbSFarhan Ali * 278d0d859bbSFarhan Ali * Validate if the virtio crypto device supports a service and 279d0d859bbSFarhan Ali * algo. 280d0d859bbSFarhan Ali * 281d0d859bbSFarhan Ali * Return true if device supports a service and algo. 282d0d859bbSFarhan Ali */ 283d0d859bbSFarhan Ali 284d0d859bbSFarhan Ali bool virtcrypto_algo_is_supported(struct virtio_crypto *vcrypto, 285d0d859bbSFarhan Ali uint32_t service, 286d0d859bbSFarhan Ali uint32_t algo) 287d0d859bbSFarhan Ali { 288d0d859bbSFarhan Ali uint32_t service_mask = 1u << service; 289d0d859bbSFarhan Ali uint32_t algo_mask = 0; 290d0d859bbSFarhan Ali bool low = true; 291d0d859bbSFarhan Ali 292d0d859bbSFarhan Ali if (algo > 31) { 293d0d859bbSFarhan Ali algo -= 32; 294d0d859bbSFarhan Ali low = false; 295d0d859bbSFarhan Ali } 296d0d859bbSFarhan Ali 297d0d859bbSFarhan Ali if (!(vcrypto->crypto_services & service_mask)) 298d0d859bbSFarhan Ali return false; 299d0d859bbSFarhan Ali 300d0d859bbSFarhan Ali switch (service) { 301d0d859bbSFarhan Ali case VIRTIO_CRYPTO_SERVICE_CIPHER: 302d0d859bbSFarhan Ali if (low) 303d0d859bbSFarhan Ali algo_mask = vcrypto->cipher_algo_l; 304d0d859bbSFarhan Ali else 305d0d859bbSFarhan Ali algo_mask = vcrypto->cipher_algo_h; 306d0d859bbSFarhan Ali break; 307d0d859bbSFarhan Ali 308d0d859bbSFarhan Ali case VIRTIO_CRYPTO_SERVICE_HASH: 309d0d859bbSFarhan Ali algo_mask = vcrypto->hash_algo; 310d0d859bbSFarhan Ali break; 311d0d859bbSFarhan Ali 312d0d859bbSFarhan Ali case VIRTIO_CRYPTO_SERVICE_MAC: 313d0d859bbSFarhan Ali if (low) 314d0d859bbSFarhan Ali algo_mask = vcrypto->mac_algo_l; 315d0d859bbSFarhan Ali else 316d0d859bbSFarhan Ali algo_mask = vcrypto->mac_algo_h; 317d0d859bbSFarhan Ali break; 318d0d859bbSFarhan Ali 319d0d859bbSFarhan Ali case VIRTIO_CRYPTO_SERVICE_AEAD: 320d0d859bbSFarhan Ali algo_mask = vcrypto->aead_algo; 321d0d859bbSFarhan Ali break; 322*59ca6c93Szhenwei pi 323*59ca6c93Szhenwei pi case VIRTIO_CRYPTO_SERVICE_AKCIPHER: 324*59ca6c93Szhenwei pi algo_mask = vcrypto->akcipher_algo; 325*59ca6c93Szhenwei pi break; 326d0d859bbSFarhan Ali } 327d0d859bbSFarhan Ali 328d0d859bbSFarhan Ali if (!(algo_mask & (1u << algo))) 329d0d859bbSFarhan Ali return false; 330d0d859bbSFarhan Ali 331d0d859bbSFarhan Ali return true; 332dbaf0624SGonglei } 333