Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Broadcom */ #ifndef _CIPHER_H #define _CIPHER_H #include <linux/atomic.h> #include <linux/mailbox/brcm-message.h> #include <linux/mailbox_client.h> #include <crypto/aes.h> #include <crypto/internal/hash.h> #include <crypto/internal/skcipher.h> #include <crypto/aead.h> #include <crypto/arc4.h> #include <crypto/gcm.h> #include <crypto/sha1.h> #include <crypto/sha2.h> #include <crypto/sha3.h> #include "spu.h" #include "spum.h" #include "spu2.h" /* Driver supports up to MAX_SPUS SPU blocks */ #define MAX_SPUS 16 #define ARC4_STATE_SIZE 4 #define CCM_AES_IV_SIZE 16 #define CCM_ESP_IV_SIZE 8 #define RFC4543_ICV_SIZE 16 #define MAX_KEY_SIZE ARC4_MAX_KEY_SIZE #define MAX_IV_SIZE AES_BLOCK_SIZE #define MAX_DIGEST_SIZE SHA3_512_DIGEST_SIZE #define MAX_ASSOC_SIZE 512 /* size of salt value for AES-GCM-ESP and AES-CCM-ESP */ #define GCM_ESP_SALT_SIZE 4 #define CCM_ESP_SALT_SIZE 3 #define MAX_SALT_SIZE GCM_ESP_SALT_SIZE #define GCM_ESP_SALT_OFFSET 0 #define CCM_ESP_SALT_OFFSET 1 #define GCM_ESP_DIGESTSIZE 16 #define MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE /* * Maximum number of bytes from a non-final hash request that can be deferred * until more data is available. With new crypto API framework, this * can be no more than one block of data. */ #define HASH_CARRY_MAX MAX_HASH_BLOCK_SIZE /* Force at least 4-byte alignment of all SPU message fields */ #define SPU_MSG_ALIGN 4 /* Number of times to resend mailbox message if mb queue is full */ #define SPU_MB_RETRY_MAX 1000 /* op_counts[] indexes */ enum op_type { SPU_OP_CIPHER, SPU_OP_HASH, SPU_OP_HMAC, SPU_OP_AEAD, SPU_OP_NUM }; enum spu_spu_type { SPU_TYPE_SPUM, SPU_TYPE_SPU2, }; /* * SPUM_NS2 and SPUM_NSP are the SPU-M block on Northstar 2 and Northstar Plus, * respectively. */ enum spu_spu_subtype { SPU_SUBTYPE_SPUM_NS2, SPU_SUBTYPE_SPUM_NSP, SPU_SUBTYPE_SPU2_V1, SPU_SUBTYPE_SPU2_V2 }; struct spu_type_subtype { enum spu_spu_type type; enum spu_spu_subtype subtype; }; struct cipher_op { enum spu_cipher_alg alg; enum spu_cipher_mode mode; }; struct auth_op { enum hash_alg alg; enum hash_mode mode; }; struct iproc_alg_s { u32 type; union { struct skcipher_alg skcipher; struct ahash_alg hash; struct aead_alg aead; } alg; struct cipher_op cipher_info; struct auth_op auth_info; bool auth_first; bool registered; }; /* * Buffers for a SPU request/reply message pair. All part of one structure to * allow a single alloc per request. */ struct spu_msg_buf { /* Request message fragments */ /* * SPU request message header. For SPU-M, holds MH, EMH, SCTX, BDESC, * and BD header. For SPU2, holds FMD, OMD. */ u8 bcm_spu_req_hdr[ALIGN(SPU2_HEADER_ALLOC_LEN, SPU_MSG_ALIGN)]; /* IV or counter. Size to include salt. Also used for XTS tweek. */ u8 iv_ctr[ALIGN(2 * AES_BLOCK_SIZE, SPU_MSG_ALIGN)]; /* Hash digest. request and response. */ u8 digest[ALIGN(MAX_DIGEST_SIZE, SPU_MSG_ALIGN)]; /* SPU request message padding */ u8 spu_req_pad[ALIGN(SPU_PAD_LEN_MAX, SPU_MSG_ALIGN)]; /* SPU-M request message STATUS field */ u8 tx_stat[ALIGN(SPU_TX_STATUS_LEN, SPU_MSG_ALIGN)]; /* Response message fragments */ /* SPU response message header */ u8 spu_resp_hdr[ALIGN(SPU2_HEADER_ALLOC_LEN, SPU_MSG_ALIGN)]; /* SPU response message STATUS field padding */ u8 rx_stat_pad[ALIGN(SPU_STAT_PAD_MAX, SPU_MSG_ALIGN)]; /* SPU response message STATUS field */ u8 rx_stat[ALIGN(SPU_RX_STATUS_LEN, SPU_MSG_ALIGN)]; union { /* Buffers only used for skcipher */ struct { /* * Field used for either SUPDT when RC4 is used * -OR- tweak value when XTS/AES is used */ u8 supdt_tweak[ALIGN(SPU_SUPDT_LEN, SPU_MSG_ALIGN)]; } c; /* Buffers only used for aead */ struct { /* SPU response pad for GCM data */ u8 gcmpad[ALIGN(AES_BLOCK_SIZE, SPU_MSG_ALIGN)]; /* SPU request msg padding for GCM AAD */ u8 req_aad_pad[ALIGN(SPU_PAD_LEN_MAX, SPU_MSG_ALIGN)]; /* SPU response data to be discarded */ u8 resp_aad[ALIGN(MAX_ASSOC_SIZE + MAX_IV_SIZE, SPU_MSG_ALIGN)]; } a; }; }; struct iproc_ctx_s { u8 enckey[MAX_KEY_SIZE + ARC4_STATE_SIZE]; unsigned int enckeylen; u8 authkey[MAX_KEY_SIZE + ARC4_STATE_SIZE]; unsigned int authkeylen; u8 salt[MAX_SALT_SIZE]; unsigned int salt_len; unsigned int salt_offset; u8 iv[MAX_IV_SIZE]; unsigned int digestsize; struct iproc_alg_s *alg; bool is_esp; struct cipher_op cipher; enum spu_cipher_type cipher_type; struct auth_op auth; bool auth_first; /* * The maximum length in bytes of the payload in a SPU message for this * context. For SPU-M, the payload is the combination of AAD and data. * For SPU2, the payload is just data. A value of SPU_MAX_PAYLOAD_INF * indicates that there is no limit to the length of the SPU message * payload. */ unsigned int max_payload; struct crypto_aead *fallback_cipher; /* auth_type is determined during processing of request */ u8 ipad[MAX_HASH_BLOCK_SIZE]; u8 opad[MAX_HASH_BLOCK_SIZE]; /* * Buffer to hold SPU message header template. Template is created at * setkey time for skcipher requests, since most of the fields in the * header are known at that time. At request time, just fill in a few * missing pieces related to length of data in the request and IVs, etc. */ u8 bcm_spu_req_hdr[ALIGN(SPU2_HEADER_ALLOC_LEN, SPU_MSG_ALIGN)]; /* Length of SPU request header */ u16 spu_req_hdr_len; /* Expected length of SPU response header */ u16 spu_resp_hdr_len; /* * shash descriptor - needed to perform incremental hashing in * software, when hw doesn't support it. */ struct shash_desc *shash; bool is_rfc4543; /* RFC 4543 style of GMAC */ }; /* state from iproc_reqctx_s necessary for hash state export/import */ struct spu_hash_export_s { unsigned int total_todo; unsigned int total_sent; u8 hash_carry[HASH_CARRY_MAX]; unsigned int hash_carry_len; u8 incr_hash[MAX_DIGEST_SIZE]; bool is_sw_hmac; }; struct iproc_reqctx_s { /* general context */ struct crypto_async_request *parent; /* only valid after enqueue() */ struct iproc_ctx_s *ctx; u8 chan_idx; /* Mailbox channel to be used to submit this request */ /* total todo, rx'd, and sent for this request */ unsigned int total_todo; unsigned int total_received; /* only valid for skcipher */ unsigned int total_sent; /* * num bytes sent to hw from the src sg in this request. This can differ * from total_sent for incremental hashing. total_sent includes previous * init() and update() data. src_sent does not. */ unsigned int src_sent; /* * For AEAD requests, start of associated data. This will typically * point to the beginning of the src scatterlist from the request, * since assoc data is at the beginning of the src scatterlist rather * than in its own sg. */ struct scatterlist *assoc; /* * scatterlist entry and offset to start of data for next chunk. Crypto * API src scatterlist for AEAD starts with AAD, if present. For first * chunk, src_sg is sg entry at beginning of input data (after AAD). * src_skip begins at the offset in that sg entry where data begins. */ struct scatterlist *src_sg; int src_nents; /* Number of src entries with data */ u32 src_skip; /* bytes of current sg entry already used */ /* * Same for destination. For AEAD, if there is AAD, output data must * be written at offset following AAD. */ struct scatterlist *dst_sg; int dst_nents; /* Number of dst entries with data */ u32 dst_skip; /* bytes of current sg entry already written */ /* Mailbox message used to send this request to PDC driver */ struct brcm_message mb_mssg; bool bd_suppress; /* suppress BD field in SPU response? */ /* cipher context */ bool is_encrypt; /* * CBC mode: IV. CTR mode: counter. Else empty. Used as a DMA * buffer for AEAD requests. So allocate as DMAable memory. If IV * concatenated with salt, includes the salt. */ u8 *iv_ctr; /* Length of IV or counter, in bytes */ unsigned int iv_ctr_len; /* * Hash requests can be of any size, whether initial, update, or final. * A non-final request must be submitted to the SPU as an integral * number of blocks. This may leave data at the end of the request * that is not a full block. Since the request is non-final, it cannot * be padded. So, we write the remainder to this hash_carry buffer and * hold it until the next request arrives. The carry data is then * submitted at the beginning of the data in the next SPU msg. * hash_carry_len is the number of bytes currently in hash_carry. These * fields are only used for ahash requests. */ u8 hash_carry[HASH_CARRY_MAX]; unsigned int hash_carry_len; unsigned int is_final; /* is this the final for the hash op? */ /* * Digest from incremental hash is saved here to include in next hash * operation. Cannot be stored in req->result for truncated hashes, * since result may be sized for final digest. Cannot be saved in * msg_buf because that gets deleted between incremental hash ops * and is not saved as part of export(). */ u8 incr_hash[MAX_DIGEST_SIZE]; /* hmac context */ bool is_sw_hmac; /* aead context */ struct crypto_tfm *old_tfm; crypto_completion_t old_complete; void *old_data; gfp_t gfp; /* Buffers used to build SPU request and response messages */ struct spu_msg_buf msg_buf; }; /* * Structure encapsulates a set of function pointers specific to the type of * SPU hardware running. These functions handling creation and parsing of * SPU request messages and SPU response messages. Includes hardware-specific * values read from device tree. */ struct spu_hw { void (*spu_dump_msg_hdr)(u8 *buf, unsigned int buf_len); u32 (*spu_ctx_max_payload)(enum spu_cipher_alg cipher_alg, enum spu_cipher_mode cipher_mode, unsigned int blocksize); u32 (*spu_payload_length)(u8 *spu_hdr); u16 (*spu_response_hdr_len)(u16 auth_key_len, u16 enc_key_len, bool is_hash); u16 (*spu_hash_pad_len)(enum hash_alg hash_alg, enum hash_mode hash_mode, u32 chunksize, u16 hash_block_size); u32 (*spu_gcm_ccm_pad_len)(enum spu_cipher_mode cipher_mode, unsigned int data_size); u32 (*spu_assoc_resp_len)(enum spu_cipher_mode cipher_mode, unsigned int assoc_len, unsigned int iv_len, bool is_encrypt); u8 (*spu_aead_ivlen)(enum spu_cipher_mode cipher_mode, u16 iv_len); enum hash_type (*spu_hash_type)(u32 src_sent); u32 (*spu_digest_size)(u32 digest_size, enum hash_alg alg, enum hash_type); u32 (*spu_create_request)(u8 *spu_hdr, struct spu_request_opts *req_opts, struct spu_cipher_parms *cipher_parms, struct spu_hash_parms *hash_parms, struct spu_aead_parms *aead_parms, unsigned int data_size); u16 (*spu_cipher_req_init)(u8 *spu_hdr, struct spu_cipher_parms *cipher_parms); void (*spu_cipher_req_finish)(u8 *spu_hdr, u16 spu_req_hdr_len, unsigned int is_inbound, struct spu_cipher_parms *cipher_parms, unsigned int data_size); void (*spu_request_pad)(u8 *pad_start, u32 gcm_padding, u32 hash_pad_len, enum hash_alg auth_alg, enum hash_mode auth_mode, unsigned int total_sent, u32 status_padding); u8 (*spu_xts_tweak_in_payload)(void); u8 (*spu_tx_status_len)(void); u8 (*spu_rx_status_len)(void); int (*spu_status_process)(u8 *statp); void (*spu_ccm_update_iv)(unsigned int digestsize, struct spu_cipher_parms *cipher_parms, unsigned int assoclen, unsigned int chunksize, bool is_encrypt, bool is_esp); u32 (*spu_wordalign_padlen)(u32 data_size); /* The base virtual address of the SPU hw registers */ void __iomem *reg_vbase[MAX_SPUS]; /* Version of the SPU hardware */ enum spu_spu_type spu_type; /* Sub-version of the SPU hardware */ enum spu_spu_subtype spu_subtype; /* The number of SPUs on this platform */ u32 num_spu; /* The number of SPU channels on this platform */ u32 num_chan; }; struct bcm_device_private { struct platform_device *pdev; struct spu_hw spu; atomic_t session_count; /* number of streams active */ atomic_t stream_count; /* monotonic counter for streamID's */ /* Length of BCM header. Set to 0 when hw does not expect BCM HEADER. */ u8 bcm_hdr_len; /* The index of the channel to use for the next crypto request */ atomic_t next_chan; struct dentry *debugfs_dir; struct dentry *debugfs_stats; /* Number of request bytes processed and result bytes returned */ atomic64_t bytes_in; atomic64_t bytes_out; /* Number of operations of each type */ atomic_t op_counts[SPU_OP_NUM]; atomic_t cipher_cnt[CIPHER_ALG_LAST][CIPHER_MODE_LAST]; atomic_t hash_cnt[HASH_ALG_LAST]; atomic_t hmac_cnt[HASH_ALG_LAST]; atomic_t aead_cnt[AEAD_TYPE_LAST]; /* Number of calls to setkey() for each operation type */ atomic_t setkey_cnt[SPU_OP_NUM]; /* Number of times request was resubmitted because mb was full */ atomic_t mb_no_spc; /* Number of mailbox send failures */ atomic_t mb_send_fail; /* Number of ICV check failures for AEAD messages */ atomic_t bad_icv; struct mbox_client mcl; /* Array of mailbox channel pointers, one for each channel */ struct mbox_chan **mbox; }; extern struct bcm_device_private iproc_priv; #endif |