]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mmc: sdhci-msm: convert to use custom crypto profile
authorEric Biggers <ebiggers@google.com>
Fri, 13 Dec 2024 04:19:50 +0000 (20:19 -0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Thu, 19 Dec 2024 13:43:33 +0000 (14:43 +0100)
As is being done in ufs-qcom, make the sdhci-msm driver override the
full crypto profile rather than "just" key programming and eviction.
This makes it much more straightforward to add support for
hardware-wrapped inline encryption keys.  It also makes it easy to pass
the original blk_crypto_key down to qcom_ice_program_key() once it is
updated to require the key in that form.

Signed-off-by: Eric Biggers <ebiggers@google.com>
Message-ID: <20241213041958.202565-8-ebiggers@kernel.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/cqhci-crypto.c
drivers/mmc/host/cqhci.h
drivers/mmc/host/sdhci-msm.c

index 2951911d3f78012c5e3894934488a6f07fae4e7d..cb804409340220c4a2f8501cd7d2c267b0771dd0 100644 (file)
@@ -28,16 +28,13 @@ cqhci_host_from_crypto_profile(struct blk_crypto_profile *profile)
        return mmc_from_crypto_profile(profile)->cqe_private;
 }
 
-static int cqhci_crypto_program_key(struct cqhci_host *cq_host,
-                                   const union cqhci_crypto_cfg_entry *cfg,
-                                   int slot)
+static void cqhci_crypto_program_key(struct cqhci_host *cq_host,
+                                    const union cqhci_crypto_cfg_entry *cfg,
+                                    int slot)
 {
        u32 slot_offset = cq_host->crypto_cfg_register + slot * sizeof(*cfg);
        int i;
 
-       if (cq_host->ops->program_key)
-               return cq_host->ops->program_key(cq_host, cfg, slot);
-
        /* Clear CFGE */
        cqhci_writel(cq_host, 0, slot_offset + 16 * sizeof(cfg->reg_val[0]));
 
@@ -52,7 +49,6 @@ static int cqhci_crypto_program_key(struct cqhci_host *cq_host,
        /* Write dword 16, which includes the new value of CFGE */
        cqhci_writel(cq_host, le32_to_cpu(cfg->reg_val[16]),
                     slot_offset + 16 * sizeof(cfg->reg_val[0]));
-       return 0;
 }
 
 static int cqhci_crypto_keyslot_program(struct blk_crypto_profile *profile,
@@ -69,7 +65,6 @@ static int cqhci_crypto_keyslot_program(struct blk_crypto_profile *profile,
        int i;
        int cap_idx = -1;
        union cqhci_crypto_cfg_entry cfg = {};
-       int err;
 
        BUILD_BUG_ON(CQHCI_CRYPTO_KEY_SIZE_INVALID != 0);
        for (i = 0; i < cq_host->crypto_capabilities.num_crypto_cap; i++) {
@@ -96,10 +91,10 @@ static int cqhci_crypto_keyslot_program(struct blk_crypto_profile *profile,
                memcpy(cfg.crypto_key, key->raw, key->size);
        }
 
-       err = cqhci_crypto_program_key(cq_host, &cfg, slot);
+       cqhci_crypto_program_key(cq_host, &cfg, slot);
 
        memzero_explicit(&cfg, sizeof(cfg));
-       return err;
+       return 0;
 }
 
 static int cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot)
@@ -110,7 +105,8 @@ static int cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot)
         */
        union cqhci_crypto_cfg_entry cfg = {};
 
-       return cqhci_crypto_program_key(cq_host, &cfg, slot);
+       cqhci_crypto_program_key(cq_host, &cfg, slot);
+       return 0;
 }
 
 static int cqhci_crypto_keyslot_evict(struct blk_crypto_profile *profile,
@@ -167,7 +163,6 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
        struct mmc_host *mmc = cq_host->mmc;
        struct device *dev = mmc_dev(mmc);
        struct blk_crypto_profile *profile = &mmc->crypto_profile;
-       unsigned int num_keyslots;
        unsigned int cap_idx;
        enum blk_crypto_mode_num blk_mode_num;
        unsigned int slot;
@@ -177,6 +172,9 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
            !(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS))
                goto out;
 
+       if (cq_host->ops->uses_custom_crypto_profile)
+               goto profile_initialized;
+
        cq_host->crypto_capabilities.reg_val =
                        cpu_to_le32(cqhci_readl(cq_host, CQHCI_CCAP));
 
@@ -195,9 +193,8 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
         * CCAP.CFGC is off by one, so the actual number of crypto
         * configurations (a.k.a. keyslots) is CCAP.CFGC + 1.
         */
-       num_keyslots = cq_host->crypto_capabilities.config_count + 1;
-
-       err = devm_blk_crypto_profile_init(dev, profile, num_keyslots);
+       err = devm_blk_crypto_profile_init(
+               dev, profile, cq_host->crypto_capabilities.config_count + 1);
        if (err)
                goto out;
 
@@ -225,9 +222,11 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
                        cq_host->crypto_cap_array[cap_idx].sdus_mask * 512;
        }
 
+profile_initialized:
+
        /* Clear all the keyslots so that we start in a known state. */
-       for (slot = 0; slot < num_keyslots; slot++)
-               cqhci_crypto_clear_keyslot(cq_host, slot);
+       for (slot = 0; slot < profile->num_slots; slot++)
+               profile->ll_ops.keyslot_evict(profile, NULL, slot);
 
        /* CQHCI crypto requires the use of 128-bit task descriptors. */
        cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
index fab9d74445ba7283bd56a8275cf59585040746d0..ce189a1866b9de6ceae461aa113f7ebc95b58606 100644 (file)
@@ -289,13 +289,11 @@ struct cqhci_host_ops {
                                 u64 *data);
        void (*pre_enable)(struct mmc_host *mmc);
        void (*post_disable)(struct mmc_host *mmc);
-#ifdef CONFIG_MMC_CRYPTO
-       int (*program_key)(struct cqhci_host *cq_host,
-                          const union cqhci_crypto_cfg_entry *cfg, int slot);
-#endif
        void (*set_tran_desc)(struct cqhci_host *cq_host, u8 **desc,
                              dma_addr_t addr, int len, bool end, bool dma64);
-
+#ifdef CONFIG_MMC_CRYPTO
+       bool uses_custom_crypto_profile;
+#endif
 };
 
 static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)
index 319f0ebbe652d63feed19469951054206b8e95d1..4610f067faca49e8dedab412bbfb4df0f181f1f8 100644 (file)
@@ -1807,12 +1807,19 @@ out:
 
 #ifdef CONFIG_MMC_CRYPTO
 
+static const struct blk_crypto_ll_ops sdhci_msm_crypto_ops; /* forward decl */
+
 static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
                              struct cqhci_host *cq_host)
 {
        struct mmc_host *mmc = msm_host->mmc;
+       struct blk_crypto_profile *profile = &mmc->crypto_profile;
        struct device *dev = mmc_dev(mmc);
        struct qcom_ice *ice;
+       union cqhci_crypto_capabilities caps;
+       union cqhci_crypto_cap_entry cap;
+       int err;
+       int i;
 
        if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS))
                return 0;
@@ -1827,8 +1834,37 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
                return PTR_ERR_OR_ZERO(ice);
 
        msm_host->ice = ice;
-       mmc->caps2 |= MMC_CAP2_CRYPTO;
 
+       /* Initialize the blk_crypto_profile */
+
+       caps.reg_val = cpu_to_le32(cqhci_readl(cq_host, CQHCI_CCAP));
+
+       /* The number of keyslots supported is (CFGC+1) */
+       err = devm_blk_crypto_profile_init(dev, profile, caps.config_count + 1);
+       if (err)
+               return err;
+
+       profile->ll_ops = sdhci_msm_crypto_ops;
+       profile->max_dun_bytes_supported = 4;
+       profile->dev = dev;
+
+       /*
+        * Currently this driver only supports AES-256-XTS.  All known versions
+        * of ICE support it, but to be safe make sure it is really declared in
+        * the crypto capability registers.  The crypto capability registers
+        * also give the supported data unit size(s).
+        */
+       for (i = 0; i < caps.num_crypto_cap; i++) {
+               cap.reg_val = cpu_to_le32(cqhci_readl(cq_host,
+                                                     CQHCI_CRYPTOCAP +
+                                                     i * sizeof(__le32)));
+               if (cap.algorithm_id == CQHCI_CRYPTO_ALG_AES_XTS &&
+                   cap.key_size == CQHCI_CRYPTO_KEY_SIZE_256)
+                       profile->modes_supported[BLK_ENCRYPTION_MODE_AES_256_XTS] |=
+                               cap.sdus_mask * 512;
+       }
+
+       mmc->caps2 |= MMC_CAP2_CRYPTO;
        return 0;
 }
 
@@ -1854,35 +1890,55 @@ static __maybe_unused int sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
        return 0;
 }
 
-/*
- * Program a key into a QC ICE keyslot, or evict a keyslot.  QC ICE requires
- * vendor-specific SCM calls for this; it doesn't support the standard way.
- */
-static int sdhci_msm_program_key(struct cqhci_host *cq_host,
-                                const union cqhci_crypto_cfg_entry *cfg,
-                                int slot)
+static inline struct sdhci_msm_host *
+sdhci_msm_host_from_crypto_profile(struct blk_crypto_profile *profile)
 {
-       struct sdhci_host *host = mmc_priv(cq_host->mmc);
+       struct mmc_host *mmc = mmc_from_crypto_profile(profile);
+       struct sdhci_host *host = mmc_priv(mmc);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
-       union cqhci_crypto_cap_entry cap;
 
-       if (!(cfg->config_enable & CQHCI_CRYPTO_CONFIGURATION_ENABLE))
-               return qcom_ice_evict_key(msm_host->ice, slot);
+       return msm_host;
+}
+
+/*
+ * Program a key into a QC ICE keyslot.  QC ICE requires a QC-specific SCM call
+ * for this; it doesn't support the standard way.
+ */
+static int sdhci_msm_ice_keyslot_program(struct blk_crypto_profile *profile,
+                                        const struct blk_crypto_key *key,
+                                        unsigned int slot)
+{
+       struct sdhci_msm_host *msm_host =
+               sdhci_msm_host_from_crypto_profile(profile);
 
        /* Only AES-256-XTS has been tested so far. */
-       cap = cq_host->crypto_cap_array[cfg->crypto_cap_idx];
-       if (cap.algorithm_id != CQHCI_CRYPTO_ALG_AES_XTS ||
-               cap.key_size != CQHCI_CRYPTO_KEY_SIZE_256)
-               return -EINVAL;
+       if (key->crypto_cfg.crypto_mode != BLK_ENCRYPTION_MODE_AES_256_XTS)
+               return -EOPNOTSUPP;
 
        return qcom_ice_program_key(msm_host->ice,
                                    QCOM_ICE_CRYPTO_ALG_AES_XTS,
                                    QCOM_ICE_CRYPTO_KEY_SIZE_256,
-                                   cfg->crypto_key,
-                                   cfg->data_unit_size, slot);
+                                   key->raw,
+                                   key->crypto_cfg.data_unit_size / 512,
+                                   slot);
 }
 
+static int sdhci_msm_ice_keyslot_evict(struct blk_crypto_profile *profile,
+                                      const struct blk_crypto_key *key,
+                                      unsigned int slot)
+{
+       struct sdhci_msm_host *msm_host =
+               sdhci_msm_host_from_crypto_profile(profile);
+
+       return qcom_ice_evict_key(msm_host->ice, slot);
+}
+
+static const struct blk_crypto_ll_ops sdhci_msm_crypto_ops = {
+       .keyslot_program        = sdhci_msm_ice_keyslot_program,
+       .keyslot_evict          = sdhci_msm_ice_keyslot_evict,
+};
+
 #else /* CONFIG_MMC_CRYPTO */
 
 static inline int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
@@ -1988,7 +2044,7 @@ static const struct cqhci_host_ops sdhci_msm_cqhci_ops = {
        .enable         = sdhci_msm_cqe_enable,
        .disable        = sdhci_msm_cqe_disable,
 #ifdef CONFIG_MMC_CRYPTO
-       .program_key    = sdhci_msm_program_key,
+       .uses_custom_crypto_profile = true,
 #endif
 };