Re: [PATCH v5 4/9] mmc: cqhci: add support for inline encryption
From: Ulf Hansson <hidden>
Date: 2021-01-21 13:10:03
Also in:
linux-arm-msm, linux-fscrypt, linux-mmc
On Thu, 21 Jan 2021 at 10:03, Eric Biggers [off-list ref] wrote:
From: Eric Biggers <redacted> Add support for eMMC inline encryption using the blk-crypto framework (Documentation/block/inline-encryption.rst). eMMC inline encryption support is specified by the upcoming JEDEC eMMC v5.2 specification. It is only specified for the CQ interface, not the non-CQ interface. Although the eMMC v5.2 specification hasn't been officially released yet, the crypto support was already agreed on several years ago, and it was already implemented by at least two major hardware vendors. Lots of hardware in the field already supports and uses it, e.g. Snapdragon 630 to give one example. eMMC inline encryption support is very similar to the UFS inline encryption support which was standardized in the UFS v2.1 specification and was already upstreamed. The only major difference is that eMMC limits data unit numbers to 32 bits, unlike UFS's 64 bits. Like we did with UFS, make the crypto support opt-in by individual drivers; don't enable it automatically whenever the hardware declares crypto support. This is necessary because in every case we've seen, some extra vendor-specific logic is needed to use the crypto support. Co-developed-by: Satya Tangirala <redacted> Signed-off-by: Satya Tangirala <redacted> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Satya Tangirala <redacted> Reviewed-and-tested-by: Peng Zhou [off-list ref] Signed-off-by: Eric Biggers <redacted> ---
[...]
quoted hunk ↗ jump to hunk
+/** + * cqhci_crypto_init - initialize CQHCI crypto support + * @cq_host: a cqhci host + * + * If the driver previously set MMC_CAP2_CRYPTO and the CQE declares + * CQHCI_CAP_CS, initialize the crypto support. This involves reading the + * crypto capability registers, initializing the keyslot manager, clearing all + * keyslots, and enabling 128-bit task descriptors. + * + * Return: 0 if crypto was initialized or isn't supported; whether + * MMC_CAP2_CRYPTO remains set indicates which one of those cases it is. + * Also can return a negative errno value on unexpected error. + */ +int cqhci_crypto_init(struct cqhci_host *cq_host) +{ + struct mmc_host *mmc = cq_host->mmc; + struct device *dev = mmc_dev(mmc); + struct blk_keyslot_manager *ksm = &mmc->ksm; + unsigned int num_keyslots; + unsigned int cap_idx; + enum blk_crypto_mode_num blk_mode_num; + unsigned int slot; + int err = 0; + + if (!(mmc->caps2 & MMC_CAP2_CRYPTO) || + !(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS)) + goto out; + + cq_host->crypto_capabilities.reg_val = + cpu_to_le32(cqhci_readl(cq_host, CQHCI_CCAP)); + + cq_host->crypto_cfg_register = + (u32)cq_host->crypto_capabilities.config_array_ptr * 0x100; + + cq_host->crypto_cap_array = + devm_kcalloc(dev, cq_host->crypto_capabilities.num_crypto_cap, + sizeof(cq_host->crypto_cap_array[0]), GFP_KERNEL); + if (!cq_host->crypto_cap_array) { + err = -ENOMEM; + goto out; + } + + /* + * 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_ksm_init(dev, ksm, num_keyslots); + if (err) + goto out; + + ksm->ksm_ll_ops = cqhci_ksm_ops; + ksm->dev = dev; + + /* Unfortunately, CQHCI crypto only supports 32 DUN bits. */ + ksm->max_dun_bytes_supported = 4; + + /* + * Cache all the crypto capabilities and advertise the supported crypto + * modes and data unit sizes to the block layer. + */ + for (cap_idx = 0; cap_idx < cq_host->crypto_capabilities.num_crypto_cap; + cap_idx++) { + cq_host->crypto_cap_array[cap_idx].reg_val = + cpu_to_le32(cqhci_readl(cq_host, + CQHCI_CRYPTOCAP + + cap_idx * sizeof(__le32))); + blk_mode_num = cqhci_find_blk_crypto_mode( + cq_host->crypto_cap_array[cap_idx]); + if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID) + continue; + ksm->crypto_modes_supported[blk_mode_num] |= + cq_host->crypto_cap_array[cap_idx].sdus_mask * 512; + } + + /* 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); + + /* CQHCI crypto requires the use of 128-bit task descriptors. */ + cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + + return 0; + +out: + mmc->caps2 &= ~MMC_CAP2_CRYPTO; + return err; +}diff --git a/drivers/mmc/host/cqhci-crypto.h b/drivers/mmc/host/cqhci-crypto.h new file mode 100644 index 0000000000000..60b58ee0e6256 --- /dev/null +++ b/drivers/mmc/host/cqhci-crypto.h@@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * CQHCI crypto engine (inline encryption) support + * + * Copyright 2020 Google LLC + */ + +#ifndef LINUX_MMC_CQHCI_CRYPTO_H +#define LINUX_MMC_CQHCI_CRYPTO_H + +#include <linux/mmc/host.h> + +#include "cqhci.h" + +#ifdef CONFIG_MMC_CRYPTO + +int cqhci_crypto_init(struct cqhci_host *host); + +/* + * Returns the crypto bits that should be set in bits 64-127 of the + * task descriptor. + */ +static inline u64 cqhci_crypto_prep_task_desc(struct mmc_request *mrq) +{ + if (!mrq->crypto_enabled) + return 0; + + return CQHCI_CRYPTO_ENABLE_BIT | + CQHCI_CRYPTO_KEYSLOT(mrq->crypto_key_slot) | + mrq->data_unit_num; +} + +#else /* CONFIG_MMC_CRYPTO */ + +static inline int cqhci_crypto_init(struct cqhci_host *host) +{ + return 0;
The host calling this function may have MMC_CAP2_CRYPTO set for it. When CONFIG_MMC_CRYPTO is set, cqhci_crypto_init() may unset MMC_CAP2_CRYPTO if initialization fails. It seems like we should unset MMC_CAP2_CRYPTO in this stub function as well, right?
+}
+
+static inline u64 cqhci_crypto_prep_task_desc(struct mmc_request *mrq)
+{
+ return 0;
+}
+
+#endif /* !CONFIG_MMC_CRYPTO */
+
+#endif /* LINUX_MMC_CQHCI_CRYPTO_H */[...] Kind regards Uffe