Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: atmel-i2c - add support for SHA204A random number generator

The Linaro/96boards Secure96 mezzanine contains (among other things)
an Atmel SHA204A symmetric crypto processor. This chip implements a
number of different functionalities, but one that is highly useful
for many different 96boards platforms is the random number generator.

So let's implement a driver for the SHA204A, and for the time being,
implement support for the random number generator only.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Ard Biesheuvel and committed by
Herbert Xu
da001fb6 c34a3201

+211
+14
drivers/crypto/Kconfig
··· 536 536 To compile this driver as a module, choose M here: the module 537 537 will be called atmel-ecc. 538 538 539 + config CRYPTO_DEV_ATMEL_SHA204A 540 + tristate "Support for Microchip / Atmel SHA accelerator and RNG" 541 + depends on I2C 542 + select CRYPTO_DEV_ATMEL_I2C 543 + select HW_RANDOM 544 + help 545 + Microhip / Atmel SHA accelerator and RNG. 546 + Select this if you want to use the Microchip / Atmel SHA204A 547 + module as a random number generator. (Other functions of the 548 + chip are currently not exposed by this driver) 549 + 550 + To compile this driver as a module, choose M here: the module 551 + will be called atmel-sha204a. 552 + 539 553 config CRYPTO_DEV_CCP 540 554 bool "Support for AMD Secure Processor" 541 555 depends on ((X86 && PCI) || (ARM64 && (OF_ADDRESS || ACPI))) && HAS_IOMEM
+1
drivers/crypto/Makefile
··· 4 4 obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o 5 5 obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o 6 6 obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o 7 + obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA204A) += atmel-sha204a.o 7 8 obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/ 8 9 obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ 9 10 obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
+15
drivers/crypto/atmel-i2c.c
··· 58 58 } 59 59 EXPORT_SYMBOL(atmel_i2c_init_read_cmd); 60 60 61 + void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd) 62 + { 63 + cmd->word_addr = COMMAND; 64 + cmd->opcode = OPCODE_RANDOM; 65 + cmd->param1 = 0; 66 + cmd->param2 = 0; 67 + cmd->count = RANDOM_COUNT; 68 + 69 + atmel_i2c_checksum(cmd); 70 + 71 + cmd->msecs = MAX_EXEC_TIME_RANDOM; 72 + cmd->rxsize = RANDOM_RSP_SIZE; 73 + } 74 + EXPORT_SYMBOL(atmel_i2c_init_random_cmd); 75 + 61 76 void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid) 62 77 { 63 78 cmd->word_addr = COMMAND;
+10
drivers/crypto/atmel-i2c.h
··· 7 7 #ifndef __ATMEL_I2C_H__ 8 8 #define __ATMEL_I2C_H__ 9 9 10 + #include <linux/hw_random.h> 11 + 10 12 #define ATMEL_ECC_PRIORITY 300 11 13 12 14 #define COMMAND 0x03 /* packet function */ ··· 30 28 #define GENKEY_RSP_SIZE (ATMEL_ECC_PUBKEY_SIZE + \ 31 29 CMD_OVERHEAD_SIZE) 32 30 #define READ_RSP_SIZE (4 + CMD_OVERHEAD_SIZE) 31 + #define RANDOM_RSP_SIZE (32 + CMD_OVERHEAD_SIZE) 33 32 #define MAX_RSP_SIZE GENKEY_RSP_SIZE 34 33 35 34 /** ··· 99 96 #define MAX_EXEC_TIME_ECDH 58 100 97 #define MAX_EXEC_TIME_GENKEY 115 101 98 #define MAX_EXEC_TIME_READ 1 99 + #define MAX_EXEC_TIME_RANDOM 50 102 100 103 101 /* Command opcode */ 104 102 #define OPCODE_ECDH 0x43 105 103 #define OPCODE_GENKEY 0x40 106 104 #define OPCODE_READ 0x02 105 + #define OPCODE_RANDOM 0x1b 107 106 108 107 /* Definitions for the READ Command */ 109 108 #define READ_COUNT 7 109 + 110 + /* Definitions for the RANDOM Command */ 111 + #define RANDOM_COUNT 7 110 112 111 113 /* Definitions for the GenKey Command */ 112 114 #define GENKEY_COUNT 7 ··· 150 142 u8 wake_token[WAKE_TOKEN_MAX_SIZE]; 151 143 size_t wake_token_sz; 152 144 atomic_t tfm_count ____cacheline_aligned; 145 + struct hwrng hwrng; 153 146 }; 154 147 155 148 /** ··· 188 179 int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd); 189 180 190 181 void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd); 182 + void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd); 191 183 void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid); 192 184 int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, 193 185 struct scatterlist *pubkey);
+171
drivers/crypto/atmel-sha204a.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Microchip / Atmel SHA204A (I2C) driver. 4 + * 5 + * Copyright (c) 2019 Linaro, Ltd. <ard.biesheuvel@linaro.org> 6 + */ 7 + 8 + #include <linux/delay.h> 9 + #include <linux/device.h> 10 + #include <linux/err.h> 11 + #include <linux/errno.h> 12 + #include <linux/i2c.h> 13 + #include <linux/init.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/scatterlist.h> 17 + #include <linux/slab.h> 18 + #include <linux/workqueue.h> 19 + #include "atmel-i2c.h" 20 + 21 + static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data, 22 + void *areq, int status) 23 + { 24 + struct atmel_i2c_client_priv *i2c_priv = work_data->ctx; 25 + struct hwrng *rng = areq; 26 + 27 + if (status) 28 + dev_warn_ratelimited(&i2c_priv->client->dev, 29 + "i2c transaction failed (%d)\n", 30 + status); 31 + 32 + rng->priv = (unsigned long)work_data; 33 + atomic_dec(&i2c_priv->tfm_count); 34 + } 35 + 36 + static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data, 37 + size_t max) 38 + { 39 + struct atmel_i2c_client_priv *i2c_priv; 40 + struct atmel_i2c_work_data *work_data; 41 + 42 + i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng); 43 + 44 + /* keep maximum 1 asynchronous read in flight at any time */ 45 + if (!atomic_add_unless(&i2c_priv->tfm_count, 1, 1)) 46 + return 0; 47 + 48 + if (rng->priv) { 49 + work_data = (struct atmel_i2c_work_data *)rng->priv; 50 + max = min(sizeof(work_data->cmd.data), max); 51 + memcpy(data, &work_data->cmd.data, max); 52 + rng->priv = 0; 53 + } else { 54 + work_data = kmalloc(sizeof(*work_data), GFP_ATOMIC); 55 + if (!work_data) 56 + return -ENOMEM; 57 + 58 + work_data->ctx = i2c_priv; 59 + work_data->client = i2c_priv->client; 60 + 61 + max = 0; 62 + } 63 + 64 + atmel_i2c_init_random_cmd(&work_data->cmd); 65 + atmel_i2c_enqueue(work_data, atmel_sha204a_rng_done, rng); 66 + 67 + return max; 68 + } 69 + 70 + static int atmel_sha204a_rng_read(struct hwrng *rng, void *data, size_t max, 71 + bool wait) 72 + { 73 + struct atmel_i2c_client_priv *i2c_priv; 74 + struct atmel_i2c_cmd cmd; 75 + int ret; 76 + 77 + if (!wait) 78 + return atmel_sha204a_rng_read_nonblocking(rng, data, max); 79 + 80 + i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng); 81 + 82 + atmel_i2c_init_random_cmd(&cmd); 83 + 84 + ret = atmel_i2c_send_receive(i2c_priv->client, &cmd); 85 + if (ret) 86 + return ret; 87 + 88 + max = min(sizeof(cmd.data), max); 89 + memcpy(data, cmd.data, max); 90 + 91 + return max; 92 + } 93 + 94 + static int atmel_sha204a_probe(struct i2c_client *client, 95 + const struct i2c_device_id *id) 96 + { 97 + struct atmel_i2c_client_priv *i2c_priv; 98 + int ret; 99 + 100 + ret = atmel_i2c_probe(client, id); 101 + if (ret) 102 + return ret; 103 + 104 + i2c_priv = i2c_get_clientdata(client); 105 + 106 + memset(&i2c_priv->hwrng, 0, sizeof(i2c_priv->hwrng)); 107 + 108 + i2c_priv->hwrng.name = dev_name(&client->dev); 109 + i2c_priv->hwrng.read = atmel_sha204a_rng_read; 110 + i2c_priv->hwrng.quality = 1024; 111 + 112 + ret = hwrng_register(&i2c_priv->hwrng); 113 + if (ret) 114 + dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); 115 + 116 + return ret; 117 + } 118 + 119 + static int atmel_sha204a_remove(struct i2c_client *client) 120 + { 121 + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); 122 + 123 + if (atomic_read(&i2c_priv->tfm_count)) { 124 + dev_err(&client->dev, "Device is busy\n"); 125 + return -EBUSY; 126 + } 127 + 128 + if (i2c_priv->hwrng.priv) 129 + kfree((void *)i2c_priv->hwrng.priv); 130 + hwrng_unregister(&i2c_priv->hwrng); 131 + 132 + return 0; 133 + } 134 + 135 + static const struct of_device_id atmel_sha204a_dt_ids[] = { 136 + { .compatible = "atmel,atsha204a", }, 137 + { /* sentinel */ } 138 + }; 139 + MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); 140 + 141 + static const struct i2c_device_id atmel_sha204a_id[] = { 142 + { "atsha204a", 0 }, 143 + { /* sentinel */ } 144 + }; 145 + MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id); 146 + 147 + static struct i2c_driver atmel_sha204a_driver = { 148 + .probe = atmel_sha204a_probe, 149 + .remove = atmel_sha204a_remove, 150 + .id_table = atmel_sha204a_id, 151 + 152 + .driver.name = "atmel-sha204a", 153 + .driver.of_match_table = of_match_ptr(atmel_sha204a_dt_ids), 154 + }; 155 + 156 + static int __init atmel_sha204a_init(void) 157 + { 158 + return i2c_add_driver(&atmel_sha204a_driver); 159 + } 160 + 161 + static void __exit atmel_sha204a_exit(void) 162 + { 163 + flush_scheduled_work(); 164 + i2c_del_driver(&atmel_sha204a_driver); 165 + } 166 + 167 + module_init(atmel_sha204a_init); 168 + module_exit(atmel_sha204a_exit); 169 + 170 + MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 171 + MODULE_LICENSE("GPL v2");