]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
crypto: caam - Detect hardware features during algorithm registration
authorVictoria Milhoan <vicki.milhoan@freescale.com>
Wed, 5 Aug 2015 18:28:48 +0000 (11:28 -0700)
committerHerbert Xu <herbert@gondor.apana.org.au>
Mon, 10 Aug 2015 15:19:04 +0000 (23:19 +0800)
Register only algorithms supported by CAAM hardware, using the CHA
version and instantiation registers to identify hardware capabilities.

Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
Tested-by: Horia Geantă <horia.geanta@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/caamrng.c
drivers/crypto/caam/regs.h

index 3d1ca083a2acc9cc036e12fec8b7ad7381024ad7..3361259273772e47a90c4528bedcd4f9cd4a55e8 100644 (file)
@@ -4371,8 +4371,10 @@ static int __init caam_algapi_init(void)
        struct device_node *dev_node;
        struct platform_device *pdev;
        struct device *ctrldev;
-       void *priv;
+       struct caam_drv_private *priv;
        int i = 0, err = 0;
+       u32 cha_vid, cha_inst, des_inst, aes_inst, md_inst;
+       unsigned int md_limit = SHA512_DIGEST_SIZE;
        bool registered = false;
 
        dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
@@ -4402,16 +4404,39 @@ static int __init caam_algapi_init(void)
 
        INIT_LIST_HEAD(&alg_list);
 
-       /* register crypto algorithms the device supports */
+       /*
+        * Register crypto algorithms the device supports.
+        * First, detect presence and attributes of DES, AES, and MD blocks.
+        */
+       cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
+       cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+       des_inst = (cha_inst & CHA_ID_LS_DES_MASK) >> CHA_ID_LS_DES_SHIFT;
+       aes_inst = (cha_inst & CHA_ID_LS_AES_MASK) >> CHA_ID_LS_AES_SHIFT;
+       md_inst = (cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
+
+       /* If MD is present, limit digest size based on LP256 */
+       if (md_inst && ((cha_vid & CHA_ID_LS_MD_MASK) == CHA_ID_LS_MD_LP256))
+               md_limit = SHA256_DIGEST_SIZE;
+
        for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
-               /* TODO: check if h/w supports alg */
                struct caam_crypto_alg *t_alg;
+               struct caam_alg_template *alg = driver_algs + i;
+               u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK;
+
+               /* Skip DES algorithms if not supported by device */
+               if (!des_inst &&
+                   ((alg_sel == OP_ALG_ALGSEL_3DES) ||
+                    (alg_sel == OP_ALG_ALGSEL_DES)))
+                               continue;
+
+               /* Skip AES algorithms if not supported by device */
+               if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES))
+                               continue;
 
-               t_alg = caam_alg_alloc(&driver_algs[i]);
+               t_alg = caam_alg_alloc(alg);
                if (IS_ERR(t_alg)) {
                        err = PTR_ERR(t_alg);
-                       pr_warn("%s alg allocation failed\n",
-                               driver_algs[i].driver_name);
+                       pr_warn("%s alg allocation failed\n", alg->driver_name);
                        continue;
                }
 
@@ -4429,6 +4454,37 @@ static int __init caam_algapi_init(void)
 
        for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
                struct caam_aead_alg *t_alg = driver_aeads + i;
+               u32 c1_alg_sel = t_alg->caam.class1_alg_type &
+                                OP_ALG_ALGSEL_MASK;
+               u32 c2_alg_sel = t_alg->caam.class2_alg_type &
+                                OP_ALG_ALGSEL_MASK;
+               u32 alg_aai = t_alg->caam.class1_alg_type & OP_ALG_AAI_MASK;
+
+               /* Skip DES algorithms if not supported by device */
+               if (!des_inst &&
+                   ((c1_alg_sel == OP_ALG_ALGSEL_3DES) ||
+                    (c1_alg_sel == OP_ALG_ALGSEL_DES)))
+                               continue;
+
+               /* Skip AES algorithms if not supported by device */
+               if (!aes_inst && (c1_alg_sel == OP_ALG_ALGSEL_AES))
+                               continue;
+
+               /*
+                * Check support for AES algorithms not available
+                * on LP devices.
+                */
+               if ((cha_vid & CHA_ID_LS_AES_MASK) == CHA_ID_LS_AES_LP)
+                       if (alg_aai == OP_ALG_AAI_GCM)
+                               continue;
+
+               /*
+                * Skip algorithms requiring message digests
+                * if MD or MD size is not supported by device.
+                */
+               if (c2_alg_sel &&
+                   (!md_inst || (t_alg->aead.maxauthsize > md_limit)))
+                               continue;
 
                caam_aead_alg_init(t_alg);
 
index 16c03f84fd9aa3c55f5e0e76c7e5f630b19ef8ba..bb0935a3817c7f2b88eea9ccd07929487f63a9c4 100644 (file)
@@ -1883,8 +1883,10 @@ static int __init caam_algapi_hash_init(void)
        struct device_node *dev_node;
        struct platform_device *pdev;
        struct device *ctrldev;
-       void *priv;
        int i = 0, err = 0;
+       struct caam_drv_private *priv;
+       unsigned int md_limit = SHA512_DIGEST_SIZE;
+       u32 cha_inst, cha_vid;
 
        dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
        if (!dev_node) {
@@ -1910,19 +1912,40 @@ static int __init caam_algapi_hash_init(void)
        if (!priv)
                return -ENODEV;
 
+       /*
+        * Register crypto algorithms the device supports.  First, identify
+        * presence and attributes of MD block.
+        */
+       cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
+       cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+
+       /*
+        * Skip registration of any hashing algorithms if MD block
+        * is not present.
+        */
+       if (!((cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT))
+               return -ENODEV;
+
+       /* Limit digest size based on LP256 */
+       if ((cha_vid & CHA_ID_LS_MD_MASK) == CHA_ID_LS_MD_LP256)
+               md_limit = SHA256_DIGEST_SIZE;
+
        INIT_LIST_HEAD(&hash_list);
 
        /* register crypto algorithms the device supports */
        for (i = 0; i < ARRAY_SIZE(driver_hash); i++) {
-               /* TODO: check if h/w supports alg */
                struct caam_hash_alg *t_alg;
+               struct caam_hash_template *alg = driver_hash + i;
+
+               /* If MD size is not supported by device, skip registration */
+               if (alg->template_ahash.halg.digestsize > md_limit)
+                       continue;
 
                /* register hmac version */
-               t_alg = caam_hash_alloc(&driver_hash[i], true);
+               t_alg = caam_hash_alloc(alg, true);
                if (IS_ERR(t_alg)) {
                        err = PTR_ERR(t_alg);
-                       pr_warn("%s alg allocation failed\n",
-                               driver_hash[i].driver_name);
+                       pr_warn("%s alg allocation failed\n", alg->driver_name);
                        continue;
                }
 
@@ -1935,11 +1958,10 @@ static int __init caam_algapi_hash_init(void)
                        list_add_tail(&t_alg->entry, &hash_list);
 
                /* register unkeyed version */
-               t_alg = caam_hash_alloc(&driver_hash[i], false);
+               t_alg = caam_hash_alloc(alg, false);
                if (IS_ERR(t_alg)) {
                        err = PTR_ERR(t_alg);
-                       pr_warn("%s alg allocation failed\n",
-                               driver_hash[i].driver_name);
+                       pr_warn("%s alg allocation failed\n", alg->driver_name);
                        continue;
                }
 
index a1d21d5fb2ff3334d45e0fbda008bf773b9b555b..345024c224674d21da026eca51781c41b4d55118 100644 (file)
@@ -315,7 +315,7 @@ static int __init caam_rng_init(void)
        struct device_node *dev_node;
        struct platform_device *pdev;
        struct device *ctrldev;
-       void *priv;
+       struct caam_drv_private *priv;
        int err;
 
        dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
@@ -342,6 +342,10 @@ static int __init caam_rng_init(void)
        if (!priv)
                return -ENODEV;
 
+       /* Check for an instantiated RNG before registration */
+       if (!(rd_reg32(&priv->ctrl->perfmon.cha_num_ls) & CHA_ID_LS_RNG_MASK))
+               return -ENODEV;
+
        dev = caam_jr_alloc();
        if (IS_ERR(dev)) {
                pr_err("Job Ring Device allocation for transform failed\n");
index 3a2a788dadba7421817e927a5e8ec50e50c7b475..d7c3579af7915a614c689ff94e10e92ff08681ec 100644 (file)
@@ -156,18 +156,28 @@ struct jr_outentry {
 #define CHA_NUM_MS_DECONUM_SHIFT       24
 #define CHA_NUM_MS_DECONUM_MASK        (0xfull << CHA_NUM_MS_DECONUM_SHIFT)
 
-/* CHA Version IDs */
+/*
+ * CHA version IDs / instantiation bitfields
+ * Defined for use with the cha_id fields in perfmon, but the same shift/mask
+ * selectors can be used to pull out the number of instantiated blocks within
+ * cha_num fields in perfmon because the locations are the same.
+ */
 #define CHA_ID_LS_AES_SHIFT    0
-#define CHA_ID_LS_AES_MASK             (0xfull << CHA_ID_LS_AES_SHIFT)
+#define CHA_ID_LS_AES_MASK     (0xfull << CHA_ID_LS_AES_SHIFT)
+#define CHA_ID_LS_AES_LP       (0x3ull << CHA_ID_LS_AES_SHIFT)
+#define CHA_ID_LS_AES_HP       (0x4ull << CHA_ID_LS_AES_SHIFT)
 
 #define CHA_ID_LS_DES_SHIFT    4
-#define CHA_ID_LS_DES_MASK             (0xfull << CHA_ID_LS_DES_SHIFT)
+#define CHA_ID_LS_DES_MASK     (0xfull << CHA_ID_LS_DES_SHIFT)
 
 #define CHA_ID_LS_ARC4_SHIFT   8
 #define CHA_ID_LS_ARC4_MASK    (0xfull << CHA_ID_LS_ARC4_SHIFT)
 
 #define CHA_ID_LS_MD_SHIFT     12
 #define CHA_ID_LS_MD_MASK      (0xfull << CHA_ID_LS_MD_SHIFT)
+#define CHA_ID_LS_MD_LP256     (0x0ull << CHA_ID_LS_MD_SHIFT)
+#define CHA_ID_LS_MD_LP512     (0x1ull << CHA_ID_LS_MD_SHIFT)
+#define CHA_ID_LS_MD_HP                (0x2ull << CHA_ID_LS_MD_SHIFT)
 
 #define CHA_ID_LS_RNG_SHIFT    16
 #define CHA_ID_LS_RNG_MASK     (0xfull << CHA_ID_LS_RNG_SHIFT)