diff options
-rw-r--r-- | Documentation/devicetree/bindings/crypto/fsl-sec4.txt | 409 | ||||
-rw-r--r-- | arch/powerpc/boot/dts/p4080ds.dts | 95 | ||||
-rw-r--r-- | drivers/crypto/Kconfig | 2 | ||||
-rw-r--r-- | drivers/crypto/Makefile | 1 | ||||
-rw-r--r-- | drivers/crypto/caam/Kconfig | 72 | ||||
-rw-r--r-- | drivers/crypto/caam/Makefile | 8 | ||||
-rw-r--r-- | drivers/crypto/caam/caamalg.c | 1163 | ||||
-rw-r--r-- | drivers/crypto/caam/compat.h | 35 | ||||
-rw-r--r-- | drivers/crypto/caam/ctrl.c | 270 | ||||
-rw-r--r-- | drivers/crypto/caam/desc.h | 1605 | ||||
-rw-r--r-- | drivers/crypto/caam/desc_constr.h | 204 | ||||
-rw-r--r-- | drivers/crypto/caam/error.c | 248 | ||||
-rw-r--r-- | drivers/crypto/caam/error.h | 10 | ||||
-rw-r--r-- | drivers/crypto/caam/intern.h | 113 | ||||
-rw-r--r-- | drivers/crypto/caam/jr.c | 523 | ||||
-rw-r--r-- | drivers/crypto/caam/jr.h | 21 | ||||
-rw-r--r-- | drivers/crypto/caam/regs.h | 663 |
17 files changed, 5441 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt new file mode 100644 index 00000000000..fce16a85e2c --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -0,0 +1,409 @@ +===================================================================== +SEC 4 Device Tree Binding +Copyright (C) 2008-2011 Freescale Semiconductor Inc. + + CONTENTS + -Overview + -SEC 4 Node + -Job Ring Node + -Run Time Integrity Check (RTIC) Node + -Run Time Integrity Check (RTIC) Memory Node + -Secure Non-Volatile Storage (SNVS) Node + -Full Example + +NOTE: the SEC 4 is also known as Freescale's Cryptographic Accelerator +Accelerator and Assurance Module (CAAM). + +===================================================================== +Overview + +DESCRIPTION + +SEC 4 h/w can process requests from 2 types of sources. +1. DPAA Queue Interface (HW interface between Queue Manager & SEC 4). +2. Job Rings (HW interface between cores & SEC 4 registers). + +High Speed Data Path Configuration: + +HW interface between QM & SEC 4 and also BM & SEC 4, on DPAA-enabled parts +such as the P4080. The number of simultaneous dequeues the QI can make is +equal to the number of Descriptor Controller (DECO) engines in a particular +SEC version. E.g., the SEC 4.0 in the P4080 has 5 DECOs and can thus +dequeue from 5 subportals simultaneously. + +Job Ring Data Path Configuration: + +Each JR is located on a separate 4k page, they may (or may not) be made visible +in the memory partition devoted to a particular core. The P4080 has 4 JRs, so +up to 4 JRs can be configured; and all 4 JRs process requests in parallel. + +===================================================================== +P4080 SEC 4 Node + +Description + + Node defines the base address of the SEC 4 block. + This block specifies the address range of all global + configuration registers for the SEC 4 block. It + also receives interrupts from the Run Time Integrity Check + (RTIC) function within the SEC 4 block. + +PROPERTIES + + - compatible + Usage: required + Value type: <string> + Definition: Must include "fsl,p4080-sec4.0","fsl,sec-4.0" + + - #address-cells + Usage: required + Value type: <u32> + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. + + - #size-cells + Usage: required + Value type: <u32> + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. + + - reg + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies the physical + address and length of the SEC4.0 configuration registers. + registers + + - ranges + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies the physical address + range of the SEC 4.0 register space (-SNVS not included). A + triplet that includes the child address, parent address, & + length. + + - interrupts + Usage: required + Value type: <prop_encoded-array> + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: <phandle> + Definition: A single <phandle> value that points + to the interrupt parent to which the child domain + is being mapped. + + Note: All other standard properties (see the ePAPR) are allowed + but are optional. + + +EXAMPLE + crypto@300000 { + compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + }; + +===================================================================== +P4080 Job Ring (JR) Node + + Child of the crypto node defines data processing interface to SEC 4 + across the peripheral bus for purposes of processing + cryptographic descriptors. The specified address + range can be made visible to one (or more) cores. + The interrupt defined for this node is controlled within + the address range of this node. + + - compatible + Usage: required + Value type: <string> + Definition: Must include "fsl,p4080-sec4.0-job-ring","fsl,sec4.0-job-ring" + + - reg + Usage: required + Value type: <prop-encoded-array> + Definition: Specifies a two JR parameters: an offset from + the parent physical address and the length the JR registers. + + - fsl,liodn + Usage: optional-but-recommended + Value type: <prop-encoded-array> + Definition: + Specifies the LIODN to be used in conjunction with + the ppid-to-liodn table that specifies the PPID to LIODN mapping. + Needed if the PAMU is used. Value is a 12 bit value + where value is a LIODN ID for this JR. This property is + normally set by boot firmware. + + - interrupts + Usage: required + Value type: <prop_encoded-array> + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: <phandle> + Definition: A single <phandle> value that points + to the interrupt parent to which the child domain + is being mapped. + +EXAMPLE + jr@1000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x1000 0x1000>; + fsl,liodn = <0x081>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + +===================================================================== +P4080 Run Time Integrity Check (RTIC) Node + + Child node of the crypto node. Defines a register space that + contains up to 5 sets of addresses and their lengths (sizes) that + will be checked at run time. After an initial hash result is + calculated, these addresses are checked by HW to monitor any + change. If any memory is modified, a Security Violation is + triggered (see SNVS definition). + + + - compatible + Usage: required + Value type: <string> + Definition: Must include "fsl,p4080-sec4.0-rtic","fsl,sec4.0-rtic". + + - #address-cells + Usage: required + Value type: <u32> + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. Must + have a value of 1. + + - #size-cells + Usage: required + Value type: <u32> + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. Must have a value of 1. + + - reg + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies a two parameters: + an offset from the parent physical address and the length + the SEC4 registers. + + - ranges + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies the physical address + range of the SEC 4 register space (-SNVS not included). A + triplet that includes the child address, parent address, & + length. + +EXAMPLE + rtic@6000 { + compatible = "fsl,p4080-sec4.0-rtic", + "fsl,sec4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + }; + +===================================================================== +P4080 Run Time Integrity Check (RTIC) Memory Node + A child node that defines individual RTIC memory regions that are used to + perform run-time integrity check of memory areas that should not modified. + The node defines a register that contains the memory address & + length (combined) and a second register that contains the hash result + in big endian format. + + - compatible + Usage: required + Value type: <string> + Definition: Must include "fsl,p4080-sec4.0-rtic-memory","fsl,sec4.0-rtic-memory". + + - reg + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies two parameters: + an offset from the parent physical address and the length: + + 1. The location of the RTIC memory address & length registers. + 2. The location RTIC hash result. + + - fsl,rtic-region + Usage: optional-but-recommended + Value type: <prop-encoded-array> + Definition: + Specifies the HW address (36 bit address) for this region + followed by the length of the HW partition to be checked; + the address is represented as a 64 bit quantity followed + by a 32 bit length. + + - fsl,liodn + Usage: optional-but-recommended + Value type: <prop-encoded-array> + Definition: + Specifies the LIODN to be used in conjunction with + the ppid-to-liodn table that specifies the PPID to LIODN + mapping. Needed if the PAMU is used. Value is a 12 bit value + where value is a LIODN ID for this RTIC memory region. This + property is normally set by boot firmware. + +EXAMPLE + rtic-a@0 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + fsl,liodn = <0x03c>; + fsl,rtic-region = <0x12345678 0x12345678 0x12345678>; + }; + +===================================================================== +P4080 Secure Non-Volatile Storage (SNVS) Node + + Node defines address range and the associated + interrupt for the SNVS function. This function + monitors security state information & reports + security violations. + + - compatible + Usage: required + Value type: <string> + Definition: Must include "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon". + + - reg + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies the physical + address and length of the SEC4 configuration + registers. + + - interrupts + Usage: required + Value type: <prop_encoded-array> + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: <phandle> + Definition: A single <phandle> value that points + to the interrupt parent to which the child domain + is being mapped. + +EXAMPLE + sec_mon@314000 { + compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; + +===================================================================== +FULL EXAMPLE + + crypto: crypto@300000 { + compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + + sec_jr0: jr@1000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <89 2>; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <90 2>; + }; + + sec_jr3: jr@4000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x4000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <91 2>; + }; + + rtic@6000 { + compatible = "fsl,p4080-sec4.0-rtic", + "fsl,sec4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + + rtic_a: rtic-a@0 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x80>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x80>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x60 0x20 0x500 0x80>; + }; + }; + }; + + sec_mon: sec_mon@314000 { + compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; + +===================================================================== diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts index 5b7fc29dd6c..c78e8015501 100644 --- a/arch/powerpc/boot/dts/p4080ds.dts +++ b/arch/powerpc/boot/dts/p4080ds.dts @@ -1,7 +1,7 @@ /* * P4080DS Device Tree Source * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009-2011 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -33,6 +33,17 @@ dma1 = &dma1; sdhc = &sdhc; + crypto = &crypto; + sec_jr0 = &sec_jr0; + sec_jr1 = &sec_jr1; + sec_jr2 = &sec_jr2; + sec_jr3 = &sec_jr3; + rtic_a = &rtic_a; + rtic_b = &rtic_b; + rtic_c = &rtic_c; + rtic_d = &rtic_d; + sec_mon = &sec_mon; + rio0 = &rapidio0; }; @@ -410,6 +421,88 @@ dr_mode = "host"; phy_type = "ulpi"; }; + + crypto: crypto@300000 { + compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + + sec_jr0: jr@1000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <89 2>; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <90 2>; + }; + + sec_jr3: jr@4000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x4000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <91 2>; + }; + + rtic@6000 { + compatible = "fsl,p4080-sec4.0-rtic", + "fsl,sec4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + + rtic_a: rtic-a@0 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x80>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x80>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x60 0x20 0x500 0x80>; + }; + }; + }; + + sec_mon: sec_mon@314000 { + compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; }; rapidio0: rapidio@ffe0c0000 { diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index e54185223c8..a27224aa883 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -200,6 +200,8 @@ config CRYPTO_DEV_HIFN_795X_RNG Select this option if you want to enable the random number generator on the HIFN 795x crypto adapters. +source drivers/crypto/caam/Kconfig + config CRYPTO_DEV_TALITOS tristate "Talitos Freescale Security Engine (SEC)" select CRYPTO_ALGAPI diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 5203e34248d..663c5efec13 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,6 +6,7 @@ n2_crypto-y := n2_core.o n2_asm.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig new file mode 100644 index 00000000000..2d876bb98ff --- /dev/null +++ b/drivers/crypto/caam/Kconfig @@ -0,0 +1,72 @@ +config CRYPTO_DEV_FSL_CAAM + tristate "Freescale CAAM-Multicore driver backend" + depends on FSL_SOC + help + Enables the driver module for Freescale's Cryptographic Accelerator + and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). + This module adds a job ring operation interface, and configures h/w + to operate as a DPAA component automatically, depending + on h/w feature availability. + + To compile this driver as a module, choose M here: the module + will be called caam. + +config CRYPTO_DEV_FSL_CAAM_RINGSIZE + int "Job Ring size" + depends on CRYPTO_DEV_FSL_CAAM + range 2 9 + default "9" + help + Select size of Job Rings as a power of 2, within the + range 2-9 (ring size 4-512). + Examples: + 2 => 4 + 3 => 8 + 4 => 16 + 5 => 32 + 6 => 64 + 7 => 128 + 8 => 256 + 9 => 512 + +config CRYPTO_DEV_FSL_CAAM_INTC + bool "Job Ring interrupt coalescing" + depends on CRYPTO_DEV_FSL_CAAM + default y + help + Enable the Job Ring's interrupt coalescing feature. + +config CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD + int "Job Ring interrupt coalescing count threshold" + depends on CRYPTO_DEV_FSL_CAAM_INTC + range 1 255 + default 255 + help + Select number of descriptor completions to queue before + raising an interrupt, in the range 1-255. Note that a selection + of 1 functionally defeats the coalescing feature, and a selection + equal or greater than the job ring size will force timeouts. + +config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD + int "Job Ring interrupt coalescing timer threshold" + depends on CRYPTO_DEV_FSL_CAAM_INTC + range 1 65535 + default 2048 + help + Select number of bus clocks/64 to timeout in the case that one or + more descriptor completions are queued without reaching the count + threshold. Range is 1-65535. + +config CRYPTO_DEV_FSL_CAAM_CRYPTO_API + tristate "Register algorithm implementations with the Crypto API" + depends on CRYPTO_DEV_FSL_CAAM + default y + select CRYPTO_ALGAPI + select CRYPTO_AUTHENC + help + Selecting this will offload crypto for users of the + scatterlist crypto API (such as the linux native IPSec + stack) to the SEC4 via job ring. + + To compile this as a module, choose M here: the module + will be called caamalg. diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile new file mode 100644 index 00000000000..ef39011b450 --- /dev/null +++ b/drivers/crypto/caam/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the CAAM backend and dependent components +# + +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o + +caam-objs := ctrl.o jr.o error.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c new file mode 100644 index 00000000000..d7fe3d3d7db --- /dev/null +++ b/drivers/crypto/caam/caamalg.c @@ -0,0 +1,1163 @@ +/* + * caam - Freescale FSL CAAM support for crypto API + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Based on talitos crypto API driver. + * + * relationship of job descriptors to shared descriptors (SteveC Dec 10 2008): + * + * --------------- --------------- + * | JobDesc #1 |-------------------->| ShareDesc | + * | *(packet 1) | | (PDB) | + * --------------- |------------->| (hashKey) | + * . | | (cipherKey) | + * . | |-------->| (operation) | + * --------------- | | --------------- + * | JobDesc #2 |------| | + * | *(packet 2) | | + * --------------- | + * . | + * . | + * --------------- | + * | JobDesc #3 |------------ + * | *(packet 3) | + * --------------- + * + * The SharedDesc never changes for a connection unless rekeyed, but + * each packet will likely be in a different place. So all we need + * to know to process the packet is where the input is, where the + * output goes, and what context we want to process with. Context is + * in the SharedDesc, packet references in the JobDesc. + * + * So, a job desc looks like: + * + * --------------------- + * | Header | + * | ShareDesc Pointer | + * | SEQ_OUT_PTR | + * | (output buffer) | + * | SEQ_IN_PTR | + * | (input buffer) | + * | LOAD (to DECO) | + * --------------------- + */ + +#include "compat.h" + +#include "regs.h" +#include "intern.h" +#include "desc_constr.h" +#include "jr.h" +#include "error.h" + +/* + * crypto alg + */ +#define CAAM_CRA_PRIORITY 3000 +/* max key is sum of AES_MAX_KEY_SIZE, max split key size */ +#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \ + SHA512_DIGEST_SIZE * 2) +/* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ +#define CAAM_MAX_IV_LENGTH 16 + +#ifdef DEBUG +/* for print_hex_dumps with line references */ +#define xstr(s) str(s) +#define str(s) #s +#define debug(format, arg...) printk(format, arg) +#else +#define debug(format, arg...) +#endif + +/* + * per-session context + */ +struct caam_ctx { + struct device *jrdev; + u32 *sh_desc; + dma_addr_t shared_desc_phys; + u32 class1_alg_type; + u32 class2_alg_type; + u32 alg_op; + u8 *key; + dma_addr_t key_phys; + unsigned int keylen; + unsigned int enckeylen; + unsigned int authkeylen; + unsigned int split_key_len; + unsigned int split_key_pad_len; + unsigned int authsize; +}; + +static int aead_authenc_setauthsize(struct crypto_aead *authenc, + unsigned int authsize) +{ + struct caam_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + + return 0; +} + +struct split_key_result { + struct completion completion; + int err; +}; + +static void split_key_done(struct device *dev, u32 *desc, u32 err, + void *context) +{ + struct split_key_result *res = context; + +#ifdef DEBUG + dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); +#endif + if (err) { + char tmp[256]; + + dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + res->err = err; + + complete(&res->completion); +} + +/* +get a split ipad/opad key + +Split key generation----------------------------------------------- + +[00] 0xb0810008 jobdesc: stidx=1 share=never len=8 +[01] 0x04000014 key: class2->keyreg len=20 + @0xffe01000 +[03] 0x84410014 operation: cls2-op sha1 hmac init dec +[04] 0x24940000 fifold: class2 msgdata-last2 len=0 imm +[05] 0xa4000001 jump: class2 local all ->1 [06] +[06] 0x64260028 fifostr: class2 mdsplit-jdk len=40 + @0xffe04000 +*/ +static u32 gen_split_key(struct caam_ctx *ctx, const u8 *key_in, u32 authkeylen) +{ + struct device *jrdev = ctx->jrdev; + u32 *desc; + struct split_key_result result; + dma_addr_t dma_addr_in, dma_addr_out; + int ret = 0; + + desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); + + init_job_desc(desc, 0); + + dma_addr_in = dma_map_single(jrdev, (void *)key_in, authkeylen, + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, dma_addr_in)) { + dev_err(jrdev, "unable to map key input memory\n"); + kfree(desc); + return -ENOMEM; + } + append_key(desc, dma_addr_in, authkeylen, CLASS_2 | + KEY_DEST_CLASS_REG); + + /* Sets MDHA up into an HMAC-INIT */ + append_operation(desc, ctx->alg_op | OP_ALG_DECRYPT | + OP_ALG_AS_INIT); + + /* + * do a FIFO_LOAD of zero, this will trigger the internal key expansion + into both pads inside MDHA + */ + append_fifo_load_as_imm(desc, NULL, 0, LDST_CLASS_2_CCB | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2); + + /* + * FIFO_STORE with the explicit split-key content store + * (0x26 output type) + */ + dma_addr_out = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len, + DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, dma_addr_out)) { + dev_err(jrdev, "unable to map key output memory\n"); + kfree(desc); + return -ENOMEM; + } + append_fifo_store(desc, dma_addr_out, ctx->split_key_len, + LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, authkeylen, 1); + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif + + result.err = 0; + init_completion(&result.completion); + + ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); + if (!ret) { + /* in progress */ + wait_for_completion_interruptible(&result.completion); + ret = result.err; +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len, 1); +#endif + } + + dma_unmap_single(jrdev, dma_addr_out, ctx->split_key_pad_len, + DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dma_addr_in, authkeylen, DMA_TO_DEVICE); + + kfree(desc); + + return ret; +} + +static int build_sh_desc_ipsec(struct caam_ctx *ctx) +{ + struct device *jrdev = ctx->jrdev; + u32 *sh_desc; + u32 *jump_cmd; + + /* build shared descriptor for this session */ + sh_desc = kmalloc(CAAM_CMD_SZ * 4 + ctx->split_key_pad_len + + ctx->enckeylen, GFP_DMA | GFP_KERNEL); + if (!sh_desc) { + dev_err(jrdev, "could not allocate shared descriptor\n"); + return -ENOMEM; + } + + init_sh_desc(sh_desc, HDR_SAVECTX | HDR_SHARE_SERIAL); + + jump_cmd = append_jump(sh_desc, CLASS_BOTH | JUMP_TEST_ALL | + JUMP_COND_SHRD | JUMP_COND_SELF); + + /* process keys, starting with class 2/authentication */ + append_key_as_imm(sh_desc, ctx->key, ctx->split_key_pad_len, + ctx->split_key_len, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + + append_key_as_imm(sh_desc, (void *)ctx->key + ctx->split_key_pad_len, + ctx->enckeylen, ctx->enckeylen, + CLASS_1 | KEY_DEST_CLASS_REG); + + /* update jump cmd now that we are at the jump target */ + set_jump_tgt_here(sh_desc, jump_cmd); + + ctx->shared_desc_phys = dma_map_single(jrdev, sh_desc, + desc_bytes(sh_desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->shared_desc_phys)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + kfree(sh_desc); + return -ENOMEM; + } + + ctx->sh_desc = sh_desc; + + return 0; +} + +static int aead_authenc_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) +{ + /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ + static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + struct rtattr *rta = (void *)key; + struct crypto_authenc_key_param *param; + unsigned int authkeylen; + unsigned int enckeylen; + int ret = 0; + + param = RTA_DATA(rta); + enckeylen = be32_to_cpu(param->enckeylen); + + key += RTA_ALIGN(rta->rta_len); + keylen -= RTA_ALIGN(rta->rta_len); + + if (keylen < enckeylen) + goto badkey; + + authkeylen = keylen - enckeylen; + + if (keylen > CAAM_MAX_KEY_SIZE) + goto badkey; + + /* Pick class 2 key length from algorithm submask */ + ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT] * 2; + ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); + +#ifdef DEBUG + printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", + keylen, enckeylen, authkeylen); + printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", + ctx->split_key_len, ctx->split_key_pad_len); + print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); +#endif + ctx->key = kmalloc(ctx->split_key_pad_len + enckeylen, + GFP_KERNEL | GFP_DMA); + if (!ctx->key) { + dev_err(jrdev, "could not allocate key output memory\n"); + return -ENOMEM; + } + + ret = gen_split_key(ctx, key, authkeylen); + if (ret) { + kfree(ctx->key); + goto badkey; + } + + /* postpend encryption key to auth split key */ + memcpy(ctx->key + ctx->split_key_pad_len, key + authkeylen, enckeylen); + + ctx->key_phys = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + + enckeylen, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->key_phys)) { + dev_err(jrdev, "unable to map key i/o memory\n"); + kfree(ctx->key); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len + enckeylen, 1); +#endif + + ctx->keylen = keylen; + ctx->enckeylen = enckeylen; + ctx->authkeylen = authkeylen; + + ret = build_sh_desc_ipsec(ctx); + if (ret) { |