diff options
| author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2019-05-24 12:26:48 -0400 |
|---|---|---|
| committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-05-30 03:35:45 -0400 |
| commit | c34a320176a59445d76783e5ee043d6ecd22d011 (patch) | |
| tree | bfd1e21b2b68dad8d2f213b9a7b59c70bde84e81 | |
| parent | 3c756aa346dfac5ae6b7fe81cb1c6380a20b1e41 (diff) | |
crypto: atmel-ecc - factor out code that can be shared
In preparation of adding support for the random number generator in
Atmel atsha204a devices, refactor the existing atmel-ecc driver (which
drives hardware that is closely related) so we can share the basic
I2C and command queuing routines.
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>
| -rw-r--r-- | drivers/crypto/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/crypto/Makefile | 1 | ||||
| -rw-r--r-- | drivers/crypto/atmel-ecc.c | 406 | ||||
| -rw-r--r-- | drivers/crypto/atmel-i2c.c | 349 | ||||
| -rw-r--r-- | drivers/crypto/atmel-i2c.h (renamed from drivers/crypto/atmel-ecc.h) | 80 |
5 files changed, 451 insertions, 389 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 119ba073f424..20674842261e 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig | |||
| @@ -519,9 +519,13 @@ config CRYPTO_DEV_ATMEL_SHA | |||
| 519 | To compile this driver as a module, choose M here: the module | 519 | To compile this driver as a module, choose M here: the module |
| 520 | will be called atmel-sha. | 520 | will be called atmel-sha. |
| 521 | 521 | ||
| 522 | config CRYPTO_DEV_ATMEL_I2C | ||
| 523 | tristate | ||
| 524 | |||
| 522 | config CRYPTO_DEV_ATMEL_ECC | 525 | config CRYPTO_DEV_ATMEL_ECC |
| 523 | tristate "Support for Microchip / Atmel ECC hw accelerator" | 526 | tristate "Support for Microchip / Atmel ECC hw accelerator" |
| 524 | depends on I2C | 527 | depends on I2C |
| 528 | select CRYPTO_DEV_ATMEL_I2C | ||
| 525 | select CRYPTO_ECDH | 529 | select CRYPTO_ECDH |
| 526 | select CRC16 | 530 | select CRC16 |
| 527 | help | 531 | help |
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index a23a7197fcd7..394e84089924 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o | 2 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o |
| 3 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o | 3 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o |
| 4 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o | 4 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o |
| 5 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o | ||
| 5 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o | 6 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o |
| 6 | obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/ | 7 | obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/ |
| 7 | obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ | 8 | obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ |
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 5705348f540f..ff02cc05affb 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * Author: Tudor Ambarus <tudor.ambarus@microchip.com> | 6 | * Author: Tudor Ambarus <tudor.ambarus@microchip.com> |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/bitrev.h> | ||
| 10 | #include <linux/crc16.h> | ||
| 11 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
| 12 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 13 | #include <linux/err.h> | 11 | #include <linux/err.h> |
| @@ -23,42 +21,11 @@ | |||
| 23 | #include <crypto/internal/kpp.h> | 21 | #include <crypto/internal/kpp.h> |
| 24 | #include <crypto/ecdh.h> | 22 | #include <crypto/ecdh.h> |
| 25 | #include <crypto/kpp.h> | 23 | #include <crypto/kpp.h> |
| 26 | #include "atmel-ecc.h" | 24 | #include "atmel-i2c.h" |
| 27 | |||
| 28 | /* Used for binding tfm objects to i2c clients. */ | ||
| 29 | struct atmel_ecc_driver_data { | ||
| 30 | struct list_head i2c_client_list; | ||
| 31 | spinlock_t i2c_list_lock; | ||
| 32 | } ____cacheline_aligned; | ||
| 33 | 25 | ||
| 34 | static struct atmel_ecc_driver_data driver_data; | 26 | static struct atmel_ecc_driver_data driver_data; |
| 35 | 27 | ||
| 36 | /** | 28 | /** |
| 37 | * atmel_ecc_i2c_client_priv - i2c_client private data | ||
| 38 | * @client : pointer to i2c client device | ||
| 39 | * @i2c_client_list_node: part of i2c_client_list | ||
| 40 | * @lock : lock for sending i2c commands | ||
| 41 | * @wake_token : wake token array of zeros | ||
| 42 | * @wake_token_sz : size in bytes of the wake_token | ||
| 43 | * @tfm_count : number of active crypto transformations on i2c client | ||
| 44 | * | ||
| 45 | * Reads and writes from/to the i2c client are sequential. The first byte | ||
| 46 | * transmitted to the device is treated as the byte size. Any attempt to send | ||
| 47 | * more than this number of bytes will cause the device to not ACK those bytes. | ||
| 48 | * After the host writes a single command byte to the input buffer, reads are | ||
| 49 | * prohibited until after the device completes command execution. Use a mutex | ||
| 50 | * when sending i2c commands. | ||
| 51 | */ | ||
| 52 | struct atmel_ecc_i2c_client_priv { | ||
| 53 | struct i2c_client *client; | ||
| 54 | struct list_head i2c_client_list_node; | ||
| 55 | struct mutex lock; | ||
| 56 | u8 wake_token[WAKE_TOKEN_MAX_SIZE]; | ||
| 57 | size_t wake_token_sz; | ||
| 58 | atomic_t tfm_count ____cacheline_aligned; | ||
| 59 | }; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * atmel_ecdh_ctx - transformation context | 29 | * atmel_ecdh_ctx - transformation context |
| 63 | * @client : pointer to i2c client device | 30 | * @client : pointer to i2c client device |
| 64 | * @fallback : used for unsupported curves or when user wants to use its own | 31 | * @fallback : used for unsupported curves or when user wants to use its own |
| @@ -80,188 +47,12 @@ struct atmel_ecdh_ctx { | |||
| 80 | bool do_fallback; | 47 | bool do_fallback; |
| 81 | }; | 48 | }; |
| 82 | 49 | ||
| 83 | /** | 50 | static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, |
| 84 | * atmel_ecc_work_data - data structure representing the work | ||
| 85 | * @ctx : transformation context. | ||
| 86 | * @cbk : pointer to a callback function to be invoked upon completion of this | ||
| 87 | * request. This has the form: | ||
| 88 | * callback(struct atmel_ecc_work_data *work_data, void *areq, u8 status) | ||
| 89 | * where: | ||
| 90 | * @work_data: data structure representing the work | ||
| 91 | * @areq : optional pointer to an argument passed with the original | ||
| 92 | * request. | ||
| 93 | * @status : status returned from the i2c client device or i2c error. | ||
| 94 | * @areq: optional pointer to a user argument for use at callback time. | ||
| 95 | * @work: describes the task to be executed. | ||
| 96 | * @cmd : structure used for communicating with the device. | ||
| 97 | */ | ||
| 98 | struct atmel_ecc_work_data { | ||
| 99 | struct atmel_ecdh_ctx *ctx; | ||
| 100 | void (*cbk)(struct atmel_ecc_work_data *work_data, void *areq, | ||
| 101 | int status); | ||
| 102 | void *areq; | ||
| 103 | struct work_struct work; | ||
| 104 | struct atmel_ecc_cmd cmd; | ||
| 105 | }; | ||
| 106 | |||
| 107 | static u16 atmel_ecc_crc16(u16 crc, const u8 *buffer, size_t len) | ||
| 108 | { | ||
| 109 | return cpu_to_le16(bitrev16(crc16(crc, buffer, len))); | ||
| 110 | } | ||
| 111 | |||
| 112 | /** | ||
| 113 | * atmel_ecc_checksum() - Generate 16-bit CRC as required by ATMEL ECC. | ||
| 114 | * CRC16 verification of the count, opcode, param1, param2 and data bytes. | ||
| 115 | * The checksum is saved in little-endian format in the least significant | ||
| 116 | * two bytes of the command. CRC polynomial is 0x8005 and the initial register | ||
| 117 | * value should be zero. | ||
| 118 | * | ||
| 119 | * @cmd : structure used for communicating with the device. | ||
| 120 | */ | ||
| 121 | static void atmel_ecc_checksum(struct atmel_ecc_cmd *cmd) | ||
| 122 | { | ||
| 123 | u8 *data = &cmd->count; | ||
| 124 | size_t len = cmd->count - CRC_SIZE; | ||
| 125 | u16 *crc16 = (u16 *)(data + len); | ||
| 126 | |||
| 127 | *crc16 = atmel_ecc_crc16(0, data, len); | ||
| 128 | } | ||
| 129 | |||
| 130 | static void atmel_ecc_init_read_cmd(struct atmel_ecc_cmd *cmd) | ||
| 131 | { | ||
| 132 | cmd->word_addr = COMMAND; | ||
| 133 | cmd->opcode = OPCODE_READ; | ||
| 134 | /* | ||
| 135 | * Read the word from Configuration zone that contains the lock bytes | ||
| 136 | * (UserExtra, Selector, LockValue, LockConfig). | ||
| 137 | */ | ||
| 138 | cmd->param1 = CONFIG_ZONE; | ||
| 139 | cmd->param2 = DEVICE_LOCK_ADDR; | ||
| 140 | cmd->count = READ_COUNT; | ||
| 141 | |||
| 142 | atmel_ecc_checksum(cmd); | ||
| 143 | |||
| 144 | cmd->msecs = MAX_EXEC_TIME_READ; | ||
| 145 | cmd->rxsize = READ_RSP_SIZE; | ||
| 146 | } | ||
| 147 | |||
| 148 | static void atmel_ecc_init_genkey_cmd(struct atmel_ecc_cmd *cmd, u16 keyid) | ||
| 149 | { | ||
| 150 | cmd->word_addr = COMMAND; | ||
| 151 | cmd->count = GENKEY_COUNT; | ||
| 152 | cmd->opcode = OPCODE_GENKEY; | ||
| 153 | cmd->param1 = GENKEY_MODE_PRIVATE; | ||
| 154 | /* a random private key will be generated and stored in slot keyID */ | ||
| 155 | cmd->param2 = cpu_to_le16(keyid); | ||
| 156 | |||
| 157 | atmel_ecc_checksum(cmd); | ||
| 158 | |||
| 159 | cmd->msecs = MAX_EXEC_TIME_GENKEY; | ||
| 160 | cmd->rxsize = GENKEY_RSP_SIZE; | ||
| 161 | } | ||
| 162 | |||
| 163 | static int atmel_ecc_init_ecdh_cmd(struct atmel_ecc_cmd *cmd, | ||
| 164 | struct scatterlist *pubkey) | ||
| 165 | { | ||
| 166 | size_t copied; | ||
| 167 | |||
| 168 | cmd->word_addr = COMMAND; | ||
| 169 | cmd->count = ECDH_COUNT; | ||
| 170 | cmd->opcode = OPCODE_ECDH; | ||
| 171 | cmd->param1 = ECDH_PREFIX_MODE; | ||
| 172 | /* private key slot */ | ||
| 173 | cmd->param2 = cpu_to_le16(DATA_SLOT_2); | ||
| 174 | |||
| 175 | /* | ||
| 176 | * The device only supports NIST P256 ECC keys. The public key size will | ||
| 177 | * always be the same. Use a macro for the key size to avoid unnecessary | ||
| 178 | * computations. | ||
| 179 | */ | ||
| 180 | copied = sg_copy_to_buffer(pubkey, | ||
| 181 | sg_nents_for_len(pubkey, | ||
| 182 | ATMEL_ECC_PUBKEY_SIZE), | ||
| 183 | cmd->data, ATMEL_ECC_PUBKEY_SIZE); | ||
| 184 | if (copied != ATMEL_ECC_PUBKEY_SIZE) | ||
| 185 | return -EINVAL; | ||
| 186 | |||
| 187 | atmel_ecc_checksum(cmd); | ||
| 188 | |||
| 189 | cmd->msecs = MAX_EXEC_TIME_ECDH; | ||
| 190 | cmd->rxsize = ECDH_RSP_SIZE; | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* | ||
| 196 | * After wake and after execution of a command, there will be error, status, or | ||
| 197 | * result bytes in the device's output register that can be retrieved by the | ||
| 198 | * system. When the length of that group is four bytes, the codes returned are | ||
| 199 | * detailed in error_list. | ||
| 200 | */ | ||
| 201 | static int atmel_ecc_status(struct device *dev, u8 *status) | ||
| 202 | { | ||
| 203 | size_t err_list_len = ARRAY_SIZE(error_list); | ||
| 204 | int i; | ||
| 205 | u8 err_id = status[1]; | ||
| 206 | |||
| 207 | if (*status != STATUS_SIZE) | ||
| 208 | return 0; | ||
| 209 | |||
| 210 | if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) | ||
| 211 | return 0; | ||
| 212 | |||
| 213 | for (i = 0; i < err_list_len; i++) | ||
| 214 | if (error_list[i].value == err_id) | ||
| 215 | break; | ||
| 216 | |||
| 217 | /* if err_id is not in the error_list then ignore it */ | ||
| 218 | if (i != err_list_len) { | ||
| 219 | dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); | ||
| 220 | return err_id; | ||
| 221 | } | ||
| 222 | |||
| 223 | return 0; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int atmel_ecc_wakeup(struct i2c_client *client) | ||
| 227 | { | ||
| 228 | struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); | ||
| 229 | u8 status[STATUS_RSP_SIZE]; | ||
| 230 | int ret; | ||
| 231 | |||
| 232 | /* | ||
| 233 | * The device ignores any levels or transitions on the SCL pin when the | ||
| 234 | * device is idle, asleep or during waking up. Don't check for error | ||
| 235 | * when waking up the device. | ||
| 236 | */ | ||
| 237 | i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz); | ||
| 238 | |||
| 239 | /* | ||
| 240 | * Wait to wake the device. Typical execution times for ecdh and genkey | ||
| 241 | * are around tens of milliseconds. Delta is chosen to 50 microseconds. | ||
| 242 | */ | ||
| 243 | usleep_range(TWHI_MIN, TWHI_MAX); | ||
| 244 | |||
| 245 | ret = i2c_master_recv(client, status, STATUS_SIZE); | ||
| 246 | if (ret < 0) | ||
| 247 | return ret; | ||
| 248 | |||
| 249 | return atmel_ecc_status(&client->dev, status); | ||
| 250 | } | ||
| 251 | |||
| 252 | static int atmel_ecc_sleep(struct i2c_client *client) | ||
| 253 | { | ||
| 254 | u8 sleep = SLEEP_TOKEN; | ||
| 255 | |||
| 256 | return i2c_master_send(client, &sleep, 1); | ||
| 257 | } | ||
| 258 | |||
| 259 | static void atmel_ecdh_done(struct atmel_ecc_work_data *work_data, void *areq, | ||
| 260 | int status) | 51 | int status) |
| 261 | { | 52 | { |
| 262 | struct kpp_request *req = areq; | 53 | struct kpp_request *req = areq; |
| 263 | struct atmel_ecdh_ctx *ctx = work_data->ctx; | 54 | struct atmel_ecdh_ctx *ctx = work_data->ctx; |
| 264 | struct atmel_ecc_cmd *cmd = &work_data->cmd; | 55 | struct atmel_i2c_cmd *cmd = &work_data->cmd; |
| 265 | size_t copied, n_sz; | 56 | size_t copied, n_sz; |
| 266 | 57 | ||
| 267 | if (status) | 58 | if (status) |
| @@ -282,82 +73,6 @@ free_work_data: | |||
| 282 | kpp_request_complete(req, status); | 73 | kpp_request_complete(req, status); |
| 283 | } | 74 | } |
| 284 | 75 | ||
| 285 | /* | ||
| 286 | * atmel_ecc_send_receive() - send a command to the device and receive its | ||
| 287 | * response. | ||
| 288 | * @client: i2c client device | ||
| 289 | * @cmd : structure used to communicate with the device | ||
| 290 | * | ||
| 291 | * After the device receives a Wake token, a watchdog counter starts within the | ||
| 292 | * device. After the watchdog timer expires, the device enters sleep mode | ||
| 293 | * regardless of whether some I/O transmission or command execution is in | ||
| 294 | * progress. If a command is attempted when insufficient time remains prior to | ||
| 295 | * watchdog timer execution, the device will return the watchdog timeout error | ||
| 296 | * code without attempting to execute the command. There is no way to reset the | ||
| 297 | * counter other than to put the device into sleep or idle mode and then | ||
| 298 | * wake it up again. | ||
| 299 | */ | ||
| 300 | static int atmel_ecc_send_receive(struct i2c_client *client, | ||
| 301 | struct atmel_ecc_cmd *cmd) | ||
| 302 | { | ||
| 303 | struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); | ||
| 304 | int ret; | ||
| 305 | |||
| 306 | mutex_lock(&i2c_priv->lock); | ||
| 307 | |||
| 308 | ret = atmel_ecc_wakeup(client); | ||
| 309 | if (ret) | ||
| 310 | goto err; | ||
| 311 | |||
| 312 | /* send the command */ | ||
| 313 | ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); | ||
| 314 | if (ret < 0) | ||
| 315 | goto err; | ||
| 316 | |||
| 317 | /* delay the appropriate amount of time for command to execute */ | ||
| 318 | msleep(cmd->msecs); | ||
| 319 | |||
| 320 | /* receive the response */ | ||
| 321 | ret = i2c_master_recv(client, cmd->data, cmd->rxsize); | ||
| 322 | if (ret < 0) | ||
| 323 | goto err; | ||
| 324 | |||
| 325 | /* put the device into low-power mode */ | ||
| 326 | ret = atmel_ecc_sleep(client); | ||
| 327 | if (ret < 0) | ||
| 328 | goto err; | ||
| 329 | |||
| 330 | mutex_unlock(&i2c_priv->lock); | ||
| 331 | return atmel_ecc_status(&client->dev, cmd->data); | ||
| 332 | err: | ||
| 333 | mutex_unlock(&i2c_priv->lock); | ||
| 334 | return ret; | ||
| 335 | } | ||
| 336 | |||
| 337 | static void atmel_ecc_work_handler(struct work_struct *work) | ||
| 338 | { | ||
| 339 | struct atmel_ecc_work_data *work_data = | ||
| 340 | container_of(work, struct atmel_ecc_work_data, work); | ||
| 341 | struct atmel_ecc_cmd *cmd = &work_data->cmd; | ||
| 342 | struct i2c_client *client = work_data->ctx->client; | ||
| 343 | int status; | ||
| 344 | |||
| 345 | status = atmel_ecc_send_receive(client, cmd); | ||
| 346 | work_data->cbk(work_data, work_data->areq, status); | ||
| 347 | } | ||
| 348 | |||
| 349 | static void atmel_ecc_enqueue(struct atmel_ecc_work_data *work_data, | ||
| 350 | void (*cbk)(struct atmel_ecc_work_data *work_data, | ||
| 351 | void *areq, int status), | ||
| 352 | void *areq) | ||
| 353 | { | ||
| 354 | work_data->cbk = (void *)cbk; | ||
| 355 | work_data->areq = areq; | ||
| 356 | |||
| 357 | INIT_WORK(&work_data->work, atmel_ecc_work_handler); | ||
| 358 | schedule_work(&work_data->work); | ||
| 359 | } | ||
| 360 | |||
| 361 | static unsigned int atmel_ecdh_supported_curve(unsigned int curve_id) | 76 | static unsigned int atmel_ecdh_supported_curve(unsigned int curve_id) |
| 362 | { | 77 | { |
| 363 | if (curve_id == ECC_CURVE_NIST_P256) | 78 | if (curve_id == ECC_CURVE_NIST_P256) |
| @@ -374,7 +89,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, | |||
| 374 | unsigned int len) | 89 | unsigned int len) |
| 375 | { | 90 | { |
| 376 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); | 91 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
| 377 | struct atmel_ecc_cmd *cmd; | 92 | struct atmel_i2c_cmd *cmd; |
| 378 | void *public_key; | 93 | void *public_key; |
| 379 | struct ecdh params; | 94 | struct ecdh params; |
| 380 | int ret = -ENOMEM; | 95 | int ret = -ENOMEM; |
| @@ -412,9 +127,9 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, | |||
| 412 | ctx->do_fallback = false; | 127 | ctx->do_fallback = false; |
| 413 | ctx->curve_id = params.curve_id; | 128 | ctx->curve_id = params.curve_id; |
| 414 | 129 | ||
| 415 | atmel_ecc_init_genkey_cmd(cmd, DATA_SLOT_2); | 130 | atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2); |
| 416 | 131 | ||
| 417 | ret = atmel_ecc_send_receive(ctx->client, cmd); | 132 | ret = atmel_i2c_send_receive(ctx->client, cmd); |
| 418 | if (ret) | 133 | if (ret) |
| 419 | goto free_public_key; | 134 | goto free_public_key; |
| 420 | 135 | ||
| @@ -444,6 +159,9 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req) | |||
| 444 | return crypto_kpp_generate_public_key(req); | 159 | return crypto_kpp_generate_public_key(req); |
| 445 | } | 160 | } |
| 446 | 161 | ||
| 162 | if (!ctx->public_key) | ||
| 163 | return -EINVAL; | ||
| 164 | |||
| 447 | /* might want less than we've got */ | 165 | /* might want less than we've got */ |
| 448 | nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len); | 166 | nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len); |
| 449 | 167 | ||
| @@ -461,7 +179,7 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) | |||
| 461 | { | 179 | { |
| 462 | struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); | 180 | struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); |
| 463 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); | 181 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
| 464 | struct atmel_ecc_work_data *work_data; | 182 | struct atmel_i2c_work_data *work_data; |
| 465 | gfp_t gfp; | 183 | gfp_t gfp; |
| 466 | int ret; | 184 | int ret; |
| 467 | 185 | ||
| @@ -482,12 +200,13 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) | |||
| 482 | return -ENOMEM; | 200 | return -ENOMEM; |
| 483 | 201 | ||
| 484 | work_data->ctx = ctx; | 202 | work_data->ctx = ctx; |
| 203 | work_data->client = ctx->client; | ||
| 485 | 204 | ||
| 486 | ret = atmel_ecc_init_ecdh_cmd(&work_data->cmd, req->src); | 205 | ret = atmel_i2c_init_ecdh_cmd(&work_data->cmd, req->src); |
| 487 | if (ret) | 206 | if (ret) |
| 488 | goto free_work_data; | 207 | goto free_work_data; |
| 489 | 208 | ||
| 490 | atmel_ecc_enqueue(work_data, atmel_ecdh_done, req); | 209 | atmel_i2c_enqueue(work_data, atmel_ecdh_done, req); |
| 491 | 210 | ||
| 492 | return -EINPROGRESS; | 211 | return -EINPROGRESS; |
| 493 | 212 | ||
| @@ -498,7 +217,7 @@ free_work_data: | |||
| 498 | 217 | ||
| 499 | static struct i2c_client *atmel_ecc_i2c_client_alloc(void) | 218 | static struct i2c_client *atmel_ecc_i2c_client_alloc(void) |
| 500 | { | 219 | { |
| 501 | struct atmel_ecc_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; | 220 | struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; |
| 502 | struct i2c_client *client = ERR_PTR(-ENODEV); | 221 | struct i2c_client *client = ERR_PTR(-ENODEV); |
| 503 | int min_tfm_cnt = INT_MAX; | 222 | int min_tfm_cnt = INT_MAX; |
| 504 | int tfm_cnt; | 223 | int tfm_cnt; |
| @@ -533,7 +252,7 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void) | |||
| 533 | 252 | ||
| 534 | static void atmel_ecc_i2c_client_free(struct i2c_client *client) | 253 | static void atmel_ecc_i2c_client_free(struct i2c_client *client) |
| 535 | { | 254 | { |
| 536 | struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); | 255 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); |
| 537 | 256 | ||
| 538 | atomic_dec(&i2c_priv->tfm_count); | 257 | atomic_dec(&i2c_priv->tfm_count); |
| 539 | } | 258 | } |
| @@ -604,99 +323,18 @@ static struct kpp_alg atmel_ecdh = { | |||
| 604 | }, | 323 | }, |
| 605 | }; | 324 | }; |
| 606 | 325 | ||
| 607 | static inline size_t atmel_ecc_wake_token_sz(u32 bus_clk_rate) | ||
| 608 | { | ||
| 609 | u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC); | ||
| 610 | |||
| 611 | /* return the size of the wake_token in bytes */ | ||
| 612 | return DIV_ROUND_UP(no_of_bits, 8); | ||
| 613 | } | ||
| 614 | |||
| 615 | static int device_sanity_check(struct i2c_client *client) | ||
| 616 | { | ||
| 617 | struct atmel_ecc_cmd *cmd; | ||
| 618 | int ret; | ||
| 619 | |||
| 620 | cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); | ||
| 621 | if (!cmd) | ||
| 622 | return -ENOMEM; | ||
| 623 | |||
| 624 | atmel_ecc_init_read_cmd(cmd); | ||
| 625 | |||
| 626 | ret = atmel_ecc_send_receive(client, cmd); | ||
| 627 | if (ret) | ||
| 628 | goto free_cmd; | ||
| 629 | |||
| 630 | /* | ||
| 631 | * It is vital that the Configuration, Data and OTP zones be locked | ||
| 632 | * prior to release into the field of the system containing the device. | ||
| 633 | * Failure to lock these zones may permit modification of any secret | ||
| 634 | * keys and may lead to other security problems. | ||
| 635 | */ | ||
| 636 | if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) { | ||
| 637 | dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n"); | ||
| 638 | ret = -ENOTSUPP; | ||
| 639 | } | ||
| 640 | |||
| 641 | /* fall through */ | ||
| 642 | free_cmd: | ||
| 643 | kfree(cmd); | ||
| 644 | return ret; | ||
| 645 | } | ||
| 646 | |||
| 647 | static int atmel_ecc_probe(struct i2c_client *client, | 326 | static int atmel_ecc_probe(struct i2c_client *client, |
| 648 | const struct i2c_device_id *id) | 327 | const struct i2c_device_id *id) |
| 649 | { | 328 | { |
| 650 | struct atmel_ecc_i2c_client_priv *i2c_priv; | 329 | struct atmel_i2c_client_priv *i2c_priv; |
| 651 | struct device *dev = &client->dev; | ||
| 652 | int ret; | 330 | int ret; |
| 653 | u32 bus_clk_rate; | ||
| 654 | 331 | ||
| 655 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | 332 | ret = atmel_i2c_probe(client, id); |
| 656 | dev_err(dev, "I2C_FUNC_I2C not supported\n"); | ||
| 657 | return -ENODEV; | ||
| 658 | } | ||
| 659 | |||
| 660 | clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); | ||
| 661 | if (!clk_rate) { | ||
| 662 | ret = device_property_read_u32(&client->adapter->dev, | ||
| 663 | "clock-frequency", &bus_clk_rate); | ||
| 664 | if (ret) { | ||
| 665 | dev_err(dev, "failed to read clock-frequency property\n"); | ||
| 666 | return ret; | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | if (bus_clk_rate > 1000000L) { | ||
| 671 | dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", | ||
| 672 | bus_clk_rate); | ||
| 673 | return -EINVAL; | ||
| 674 | } | ||
| 675 | |||
| 676 | i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); | ||
| 677 | if (!i2c_priv) | ||
| 678 | return -ENOMEM; | ||
| 679 | |||
| 680 | i2c_priv->client = client; | ||
| 681 | mutex_init(&i2c_priv->lock); | ||
| 682 | |||
| 683 | /* | ||
| 684 | * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - | ||
| 685 | * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz | ||
| 686 | * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE. | ||
| 687 | */ | ||
| 688 | i2c_priv->wake_token_sz = atmel_ecc_wake_token_sz(bus_clk_rate); | ||
| 689 | |||
| 690 | memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token)); | ||
| 691 | |||
| 692 | atomic_set(&i2c_priv->tfm_count, 0); | ||
| 693 | |||
| 694 | i2c_set_clientdata(client, i2c_priv); | ||
| 695 | |||
| 696 | ret = device_sanity_check(client); | ||
| 697 | if (ret) | 333 | if (ret) |
| 698 | return ret; | 334 | return ret; |
| 699 | 335 | ||
| 336 | i2c_priv = i2c_get_clientdata(client); | ||
| 337 | |||
| 700 | spin_lock(&driver_data.i2c_list_lock); | 338 | spin_lock(&driver_data.i2c_list_lock); |
| 701 | list_add_tail(&i2c_priv->i2c_client_list_node, | 339 | list_add_tail(&i2c_priv->i2c_client_list_node, |
| 702 | &driver_data.i2c_client_list); | 340 | &driver_data.i2c_client_list); |
| @@ -708,10 +346,10 @@ static int atmel_ecc_probe(struct i2c_client *client, | |||
| 708 | list_del(&i2c_priv->i2c_client_list_node); | 346 | list_del(&i2c_priv->i2c_client_list_node); |
| 709 | spin_unlock(&driver_data.i2c_list_lock); | 347 | spin_unlock(&driver_data.i2c_list_lock); |
| 710 | 348 | ||
| 711 | dev_err(dev, "%s alg registration failed\n", | 349 | dev_err(&client->dev, "%s alg registration failed\n", |
| 712 | atmel_ecdh.base.cra_driver_name); | 350 | atmel_ecdh.base.cra_driver_name); |
| 713 | } else { | 351 | } else { |
| 714 | dev_info(dev, "atmel ecc algorithms registered in /proc/crypto\n"); | 352 | dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n"); |
| 715 | } | 353 | } |
| 716 | 354 | ||
| 717 | return ret; | 355 | return ret; |
| @@ -719,7 +357,7 @@ static int atmel_ecc_probe(struct i2c_client *client, | |||
| 719 | 357 | ||
| 720 | static int atmel_ecc_remove(struct i2c_client *client) | 358 | static int atmel_ecc_remove(struct i2c_client *client) |
| 721 | { | 359 | { |
| 722 | struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); | 360 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); |
| 723 | 361 | ||
| 724 | /* Return EBUSY if i2c client already allocated. */ | 362 | /* Return EBUSY if i2c client already allocated. */ |
| 725 | if (atomic_read(&i2c_priv->tfm_count)) { | 363 | if (atomic_read(&i2c_priv->tfm_count)) { |
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c new file mode 100644 index 000000000000..5e099368d120 --- /dev/null +++ b/drivers/crypto/atmel-i2c.c | |||
| @@ -0,0 +1,349 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Microchip / Atmel ECC (I2C) driver. | ||
| 4 | * | ||
| 5 | * Copyright (c) 2017, Microchip Technology Inc. | ||
| 6 | * Author: Tudor Ambarus <tudor.ambarus@microchip.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/bitrev.h> | ||
| 10 | #include <linux/crc16.h> | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include <linux/errno.h> | ||
| 15 | #include <linux/i2c.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/scatterlist.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/workqueue.h> | ||
| 22 | #include "atmel-i2c.h" | ||
| 23 | |||
| 24 | /** | ||
| 25 | * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC. | ||
| 26 | * CRC16 verification of the count, opcode, param1, param2 and data bytes. | ||
| 27 | * The checksum is saved in little-endian format in the least significant | ||
| 28 | * two bytes of the command. CRC polynomial is 0x8005 and the initial register | ||
| 29 | * value should be zero. | ||
| 30 | * | ||
| 31 | * @cmd : structure used for communicating with the device. | ||
| 32 | */ | ||
| 33 | static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd) | ||
| 34 | { | ||
| 35 | u8 *data = &cmd->count; | ||
| 36 | size_t len = cmd->count - CRC_SIZE; | ||
| 37 | u16 *__crc16 = (u16 *)(data + len); | ||
| 38 | |||
| 39 | *__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len))); | ||
| 40 | } | ||
| 41 | |||
| 42 | void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd) | ||
| 43 | { | ||
| 44 | cmd->word_addr = COMMAND; | ||
| 45 | cmd->opcode = OPCODE_READ; | ||
| 46 | /* | ||
| 47 | * Read the word from Configuration zone that contains the lock bytes | ||
| 48 | * (UserExtra, Selector, LockValue, LockConfig). | ||
| 49 | */ | ||
| 50 | cmd->param1 = CONFIG_ZONE; | ||
| 51 | cmd->param2 = DEVICE_LOCK_ADDR; | ||
| 52 | cmd->count = READ_COUNT; | ||
| 53 | |||
| 54 | atmel_i2c_checksum(cmd); | ||
| 55 | |||
| 56 | cmd->msecs = MAX_EXEC_TIME_READ; | ||
| 57 | cmd->rxsize = READ_RSP_SIZE; | ||
| 58 | } | ||
| 59 | EXPORT_SYMBOL(atmel_i2c_init_read_cmd); | ||
| 60 | |||
| 61 | void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid) | ||
| 62 | { | ||
| 63 | cmd->word_addr = COMMAND; | ||
| 64 | cmd->count = GENKEY_COUNT; | ||
| 65 | cmd->opcode = OPCODE_GENKEY; | ||
| 66 | cmd->param1 = GENKEY_MODE_PRIVATE; | ||
| 67 | /* a random private key will be generated and stored in slot keyID */ | ||
| 68 | cmd->param2 = cpu_to_le16(keyid); | ||
| 69 | |||
| 70 | atmel_i2c_checksum(cmd); | ||
| 71 | |||
| 72 | cmd->msecs = MAX_EXEC_TIME_GENKEY; | ||
| 73 | cmd->rxsize = GENKEY_RSP_SIZE; | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL(atmel_i2c_init_genkey_cmd); | ||
| 76 | |||
| 77 | int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, | ||
| 78 | struct scatterlist *pubkey) | ||
| 79 | { | ||
| 80 | size_t copied; | ||
| 81 | |||
| 82 | cmd->word_addr = COMMAND; | ||
| 83 | cmd->count = ECDH_COUNT; | ||
| 84 | cmd->opcode = OPCODE_ECDH; | ||
| 85 | cmd->param1 = ECDH_PREFIX_MODE; | ||
| 86 | /* private key slot */ | ||
| 87 | cmd->param2 = cpu_to_le16(DATA_SLOT_2); | ||
| 88 | |||
| 89 | /* | ||
| 90 | * The device only supports NIST P256 ECC keys. The public key size will | ||
| 91 | * always be the same. Use a macro for the key size to avoid unnecessary | ||
| 92 | * computations. | ||
| 93 | */ | ||
| 94 | copied = sg_copy_to_buffer(pubkey, | ||
| 95 | sg_nents_for_len(pubkey, | ||
| 96 | ATMEL_ECC_PUBKEY_SIZE), | ||
| 97 | cmd->data, ATMEL_ECC_PUBKEY_SIZE); | ||
| 98 | if (copied != ATMEL_ECC_PUBKEY_SIZE) | ||
| 99 | return -EINVAL; | ||
| 100 | |||
| 101 | atmel_i2c_checksum(cmd); | ||
| 102 | |||
| 103 | cmd->msecs = MAX_EXEC_TIME_ECDH; | ||
| 104 | cmd->rxsize = ECDH_RSP_SIZE; | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | EXPORT_SYMBOL(atmel_i2c_init_ecdh_cmd); | ||
| 109 | |||
| 110 | /* | ||
| 111 | * After wake and after execution of a command, there will be error, status, or | ||
| 112 | * result bytes in the device's output register that can be retrieved by the | ||
| 113 | * system. When the length of that group is four bytes, the codes returned are | ||
| 114 | * detailed in error_list. | ||
| 115 | */ | ||
| 116 | static int atmel_i2c_status(struct device *dev, u8 *status) | ||
| 117 | { | ||
| 118 | size_t err_list_len = ARRAY_SIZE(error_list); | ||
| 119 | int i; | ||
| 120 | u8 err_id = status[1]; | ||
| 121 | |||
| 122 | if (*status != STATUS_SIZE) | ||
| 123 | return 0; | ||
| 124 | |||
| 125 | if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) | ||
| 126 | return 0; | ||
| 127 | |||
| 128 | for (i = 0; i < err_list_len; i++) | ||
| 129 | if (error_list[i].value == err_id) | ||
| 130 | break; | ||
| 131 | |||
| 132 | /* if err_id is not in the error_list then ignore it */ | ||
| 133 | if (i != err_list_len) { | ||
| 134 | dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); | ||
| 135 | return err_id; | ||
| 136 | } | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int atmel_i2c_wakeup(struct i2c_client *client) | ||
| 142 | { | ||
| 143 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); | ||
| 144 | u8 status[STATUS_RSP_SIZE]; | ||
| 145 | int ret; | ||
| 146 | |||
| 147 | /* | ||
| 148 | * The device ignores any levels or transitions on the SCL pin when the | ||
| 149 | * device is idle, asleep or during waking up. Don't check for error | ||
| 150 | * when waking up the device. | ||
| 151 | */ | ||
| 152 | i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz); | ||
| 153 | |||
| 154 | /* | ||
| 155 | * Wait to wake the device. Typical execution times for ecdh and genkey | ||
| 156 | * are around tens of milliseconds. Delta is chosen to 50 microseconds. | ||
| 157 | */ | ||
| 158 | usleep_range(TWHI_MIN, TWHI_MAX); | ||
| 159 | |||
| 160 | ret = i2c_master_recv(client, status, STATUS_SIZE); | ||
| 161 | if (ret < 0) | ||
| 162 | return ret; | ||
| 163 | |||
| 164 | return atmel_i2c_status(&client->dev, status); | ||
| 165 | } | ||
| 166 | |||
| 167 | static int atmel_i2c_sleep(struct i2c_client *client) | ||
| 168 | { | ||
| 169 | u8 sleep = SLEEP_TOKEN; | ||
| 170 | |||
| 171 | return i2c_master_send(client, &sleep, 1); | ||
| 172 | } | ||
| 173 | |||
| 174 | /* | ||
| 175 | * atmel_i2c_send_receive() - send a command to the device and receive its | ||
| 176 | * response. | ||
| 177 | * @client: i2c client device | ||
| 178 | * @cmd : structure used to communicate with the device | ||
| 179 | * | ||
| 180 | * After the device receives a Wake token, a watchdog counter starts within the | ||
| 181 | * device. After the watchdog timer expires, the device enters sleep mode | ||
| 182 | * regardless of whether some I/O transmission or command execution is in | ||
| 183 | * progress. If a command is attempted when insufficient time remains prior to | ||
| 184 | * watchdog timer execution, the device will return the watchdog timeout error | ||
| 185 | * code without attempting to execute the command. There is no way to reset the | ||
| 186 | * counter other than to put the device into sleep or idle mode and then | ||
| 187 | * wake it up again. | ||
| 188 | */ | ||
| 189 | int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd) | ||
| 190 | { | ||
| 191 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); | ||
| 192 | int ret; | ||
| 193 | |||
| 194 | mutex_lock(&i2c_priv->lock); | ||
| 195 | |||
| 196 | ret = atmel_i2c_wakeup(client); | ||
| 197 | if (ret) | ||
| 198 | goto err; | ||
| 199 | |||
| 200 | /* send the command */ | ||
| 201 | ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); | ||
| 202 | if (ret < 0) | ||
| 203 | goto err; | ||
| 204 | |||
| 205 | /* delay the appropriate amount of time for command to execute */ | ||
| 206 | msleep(cmd->msecs); | ||
| 207 | |||
| 208 | /* receive the response */ | ||
| 209 | ret = i2c_master_recv(client, cmd->data, cmd->rxsize); | ||
| 210 | if (ret < 0) | ||
| 211 | goto err; | ||
| 212 | |||
| 213 | /* put the device into low-power mode */ | ||
| 214 | ret = atmel_i2c_sleep(client); | ||
| 215 | if (ret < 0) | ||
| 216 | goto err; | ||
| 217 | |||
| 218 | mutex_unlock(&i2c_priv->lock); | ||
| 219 | return atmel_i2c_status(&client->dev, cmd->data); | ||
| 220 | err: | ||
| 221 | mutex_unlock(&i2c_priv->lock); | ||
| 222 | return ret; | ||
| 223 | } | ||
| 224 | EXPORT_SYMBOL(atmel_i2c_send_receive); | ||
| 225 | |||
| 226 | static void atmel_i2c_work_handler(struct work_struct *work) | ||
| 227 | { | ||
| 228 | struct atmel_i2c_work_data *work_data = | ||
| 229 | container_of(work, struct atmel_i2c_work_data, work); | ||
| 230 | struct atmel_i2c_cmd *cmd = &work_data->cmd; | ||
| 231 | struct i2c_client *client = work_data->client; | ||
| 232 | int status; | ||
| 233 | |||
| 234 | status = atmel_i2c_send_receive(client, cmd); | ||
| 235 | work_data->cbk(work_data, work_data->areq, status); | ||
| 236 | } | ||
| 237 | |||
| 238 | void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, | ||
| 239 | void (*cbk)(struct atmel_i2c_work_data *work_data, | ||
| 240 | void *areq, int status), | ||
| 241 | void *areq) | ||
| 242 | { | ||
| 243 | work_data->cbk = (void *)cbk; | ||
| 244 | work_data->areq = areq; | ||
| 245 | |||
| 246 | INIT_WORK(&work_data->work, atmel_i2c_work_handler); | ||
| 247 | schedule_work(&work_data->work); | ||
| 248 | } | ||
| 249 | EXPORT_SYMBOL(atmel_i2c_enqueue); | ||
| 250 | |||
| 251 | static inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate) | ||
| 252 | { | ||
| 253 | u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC); | ||
| 254 | |||
| 255 | /* return the size of the wake_token in bytes */ | ||
| 256 | return DIV_ROUND_UP(no_of_bits, 8); | ||
| 257 | } | ||
| 258 | |||
| 259 | static int device_sanity_check(struct i2c_client *client) | ||
| 260 | { | ||
| 261 | struct atmel_i2c_cmd *cmd; | ||
| 262 | int ret; | ||
| 263 | |||
| 264 | cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); | ||
| 265 | if (!cmd) | ||
| 266 | return -ENOMEM; | ||
| 267 | |||
| 268 | atmel_i2c_init_read_cmd(cmd); | ||
| 269 | |||
| 270 | ret = atmel_i2c_send_receive(client, cmd); | ||
| 271 | if (ret) | ||
| 272 | goto free_cmd; | ||
| 273 | |||
| 274 | /* | ||
| 275 | * It is vital that the Configuration, Data and OTP zones be locked | ||
| 276 | * prior to release into the field of the system containing the device. | ||
| 277 | * Failure to lock these zones may permit modification of any secret | ||
| 278 | * keys and may lead to other security problems. | ||
| 279 | */ | ||
| 280 | if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) { | ||
| 281 | dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n"); | ||
| 282 | ret = -ENOTSUPP; | ||
| 283 | } | ||
| 284 | |||
| 285 | /* fall through */ | ||
| 286 | free_cmd: | ||
| 287 | kfree(cmd); | ||
| 288 | return ret; | ||
| 289 | } | ||
| 290 | |||
| 291 | int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
| 292 | { | ||
| 293 | struct atmel_i2c_client_priv *i2c_priv; | ||
| 294 | struct device *dev = &client->dev; | ||
| 295 | int ret; | ||
| 296 | u32 bus_clk_rate; | ||
| 297 | |||
| 298 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
| 299 | dev_err(dev, "I2C_FUNC_I2C not supported\n"); | ||
| 300 | return -ENODEV; | ||
| 301 | } | ||
| 302 | |||
| 303 | bus_clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); | ||
| 304 | if (!bus_clk_rate) { | ||
| 305 | ret = device_property_read_u32(&client->adapter->dev, | ||
| 306 | "clock-frequency", &bus_clk_rate); | ||
| 307 | if (ret) { | ||
| 308 | dev_err(dev, "failed to read clock-frequency property\n"); | ||
| 309 | return ret; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | if (bus_clk_rate > 1000000L) { | ||
| 314 | dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", | ||
| 315 | bus_clk_rate); | ||
| 316 | return -EINVAL; | ||
| 317 | } | ||
| 318 | |||
| 319 | i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); | ||
| 320 | if (!i2c_priv) | ||
| 321 | return -ENOMEM; | ||
| 322 | |||
| 323 | i2c_priv->client = client; | ||
| 324 | mutex_init(&i2c_priv->lock); | ||
| 325 | |||
| 326 | /* | ||
| 327 | * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - | ||
| 328 | * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz | ||
| 329 | * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE. | ||
| 330 | */ | ||
| 331 | i2c_priv->wake_token_sz = atmel_i2c_wake_token_sz(bus_clk_rate); | ||
| 332 | |||
| 333 | memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token)); | ||
| 334 | |||
| 335 | atomic_set(&i2c_priv->tfm_count, 0); | ||
| 336 | |||
| 337 | i2c_set_clientdata(client, i2c_priv); | ||
| 338 | |||
| 339 | ret = device_sanity_check(client); | ||
| 340 | if (ret) | ||
| 341 | return ret; | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | EXPORT_SYMBOL(atmel_i2c_probe); | ||
| 346 | |||
| 347 | MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>"); | ||
| 348 | MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver"); | ||
| 349 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/crypto/atmel-ecc.h b/drivers/crypto/atmel-i2c.h index 643a3b947338..82de5166acfa 100644 --- a/drivers/crypto/atmel-ecc.h +++ b/drivers/crypto/atmel-i2c.h | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | * Author: Tudor Ambarus <tudor.ambarus@microchip.com> | 4 | * Author: Tudor Ambarus <tudor.ambarus@microchip.com> |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #ifndef __ATMEL_ECC_H__ | 7 | #ifndef __ATMEL_I2C_H__ |
| 8 | #define __ATMEL_ECC_H__ | 8 | #define __ATMEL_I2C_H__ |
| 9 | 9 | ||
| 10 | #define ATMEL_ECC_PRIORITY 300 | 10 | #define ATMEL_ECC_PRIORITY 300 |
| 11 | 11 | ||
| @@ -31,7 +31,7 @@ | |||
| 31 | #define MAX_RSP_SIZE GENKEY_RSP_SIZE | 31 | #define MAX_RSP_SIZE GENKEY_RSP_SIZE |
| 32 | 32 | ||
| 33 | /** | 33 | /** |
| 34 | * atmel_ecc_cmd - structure used for communicating with the device. | 34 | * atmel_i2c_cmd - structure used for communicating with the device. |
| 35 | * @word_addr: indicates the function of the packet sent to the device. This | 35 | * @word_addr: indicates the function of the packet sent to the device. This |
| 36 | * byte should have a value of COMMAND for normal operation. | 36 | * byte should have a value of COMMAND for normal operation. |
| 37 | * @count : number of bytes to be transferred to (or from) the device. | 37 | * @count : number of bytes to be transferred to (or from) the device. |
| @@ -42,7 +42,7 @@ | |||
| 42 | * @rxsize : size of the data received from i2c client. | 42 | * @rxsize : size of the data received from i2c client. |
| 43 | * @msecs : command execution time in milliseconds | 43 | * @msecs : command execution time in milliseconds |
| 44 | */ | 44 | */ |
| 45 | struct atmel_ecc_cmd { | 45 | struct atmel_i2c_cmd { |
| 46 | u8 word_addr; | 46 | u8 word_addr; |
| 47 | u8 count; | 47 | u8 count; |
| 48 | u8 opcode; | 48 | u8 opcode; |
| @@ -113,4 +113,74 @@ static const struct { | |||
| 113 | #define ECDH_COUNT 71 | 113 | #define ECDH_COUNT 71 |
| 114 | #define ECDH_PREFIX_MODE 0x00 | 114 | #define ECDH_PREFIX_MODE 0x00 |
| 115 | 115 | ||
| 116 | #endif /* __ATMEL_ECC_H__ */ | 116 | /* Used for binding tfm objects to i2c clients. */ |
| 117 | struct atmel_ecc_driver_data { | ||
| 118 | struct list_head i2c_client_list; | ||
| 119 | spinlock_t i2c_list_lock; | ||
| 120 | } ____cacheline_aligned; | ||
| 121 | |||
| 122 | /** | ||
| 123 | * atmel_i2c_client_priv - i2c_client private data | ||
| 124 | * @client : pointer to i2c client device | ||
| 125 | * @i2c_client_list_node: part of i2c_client_list | ||
| 126 | * @lock : lock for sending i2c commands | ||
| 127 | * @wake_token : wake token array of zeros | ||
| 128 | * @wake_token_sz : size in bytes of the wake_token | ||
| 129 | * @tfm_count : number of active crypto transformations on i2c client | ||
| 130 | * | ||
| 131 | * Reads and writes from/to the i2c client are sequential. The first byte | ||
| 132 | * transmitted to the device is treated as the byte size. Any attempt to send | ||
| 133 | * more than this number of bytes will cause the device to not ACK those bytes. | ||
| 134 | * After the host writes a single command byte to the input buffer, reads are | ||
| 135 | * prohibited until after the device completes command execution. Use a mutex | ||
| 136 | * when sending i2c commands. | ||
| 137 | */ | ||
| 138 | struct atmel_i2c_client_priv { | ||
| 139 | struct i2c_client *client; | ||
| 140 | struct list_head i2c_client_list_node; | ||
| 141 | struct mutex lock; | ||
| 142 | u8 wake_token[WAKE_TOKEN_MAX_SIZE]; | ||
| 143 | size_t wake_token_sz; | ||
| 144 | atomic_t tfm_count ____cacheline_aligned; | ||
| 145 | }; | ||
| 146 | |||
| 147 | /** | ||
| 148 | * atmel_i2c_work_data - data structure representing the work | ||
| 149 | * @ctx : transformation context. | ||
| 150 | * @cbk : pointer to a callback function to be invoked upon completion of this | ||
| 151 | * request. This has the form: | ||
| 152 | * callback(struct atmel_i2c_work_data *work_data, void *areq, u8 status) | ||
| 153 | * where: | ||
| 154 | * @work_data: data structure representing the work | ||
| 155 | * @areq : optional pointer to an argument passed with the original | ||
| 156 | * request. | ||
| 157 | * @status : status returned from the i2c client device or i2c error. | ||
| 158 | * @areq: optional pointer to a user argument for use at callback time. | ||
| 159 | * @work: describes the task to be executed. | ||
| 160 | * @cmd : structure used for communicating with the device. | ||
| 161 | */ | ||
| 162 | struct atmel_i2c_work_data { | ||
| 163 | void *ctx; | ||
| 164 | struct i2c_client *client; | ||
| 165 | void (*cbk)(struct atmel_i2c_work_data *work_data, void *areq, | ||
| 166 | int status); | ||
| 167 | void *areq; | ||
| 168 | struct work_struct work; | ||
| 169 | struct atmel_i2c_cmd cmd; | ||
| 170 | }; | ||
| 171 | |||
| 172 | int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); | ||
| 173 | |||
| 174 | void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, | ||
| 175 | void (*cbk)(struct atmel_i2c_work_data *work_data, | ||
| 176 | void *areq, int status), | ||
| 177 | void *areq); | ||
| 178 | |||
| 179 | int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd); | ||
| 180 | |||
| 181 | void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd); | ||
| 182 | void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid); | ||
| 183 | int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, | ||
| 184 | struct scatterlist *pubkey); | ||
| 185 | |||
| 186 | #endif /* __ATMEL_I2C_H__ */ | ||
