diff options
author | Eric Biggers <ebiggers@google.com> | 2021-01-25 21:38:05 +0300 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2021-02-01 14:02:33 +0300 |
commit | 1e80709bdbfc1e1f3cac0ba8ed9a58f5789bcf51 (patch) | |
tree | a71aeac8841ea628f4e3f77b9734a7f70c419c8e /drivers/mmc/host/cqhci-core.c | |
parent | ee49d0321f02596a046173be16fddcdfb8ceb7c1 (diff) | |
download | linux-1e80709bdbfc1e1f3cac0ba8ed9a58f5789bcf51.tar.xz |
mmc: cqhci: add support for inline encryption
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 <satyat@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Satya Tangirala <satyat@google.com>
Reviewed-and-tested-by: Peng Zhou <peng.zhou@mediatek.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Link: https://lore.kernel.org/r/20210125183810.198008-5-ebiggers@kernel.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/cqhci-core.c')
-rw-r--r-- | drivers/mmc/host/cqhci-core.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index ad7c9acff172..93b0432bb601 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -18,6 +18,7 @@ #include <linux/mmc/card.h> #include "cqhci.h" +#include "cqhci-crypto.h" #define DCMD_SLOT 31 #define NUM_SLOTS 32 @@ -258,6 +259,9 @@ static void __cqhci_enable(struct cqhci_host *cq_host) if (cq_host->caps & CQHCI_TASK_DESC_SZ_128) cqcfg |= CQHCI_TASK_DESC_SZ; + if (mmc->caps2 & MMC_CAP2_CRYPTO) + cqcfg |= CQHCI_CRYPTO_GENERAL_ENABLE; + cqhci_writel(cq_host, cqcfg, CQHCI_CFG); cqhci_writel(cq_host, lower_32_bits(cq_host->desc_dma_base), @@ -430,7 +434,7 @@ static void cqhci_prep_task_desc(struct mmc_request *mrq, task_desc[0] = cpu_to_le64(desc0); if (cq_host->caps & CQHCI_TASK_DESC_SZ_128) { - u64 desc1 = 0; + u64 desc1 = cqhci_crypto_prep_task_desc(mrq); task_desc[1] = cpu_to_le64(desc1); @@ -681,6 +685,7 @@ static void cqhci_error_irq(struct mmc_host *mmc, u32 status, int cmd_error, struct cqhci_host *cq_host = mmc->cqe_private; struct cqhci_slot *slot; u32 terri; + u32 tdpe; int tag; spin_lock(&cq_host->lock); @@ -719,6 +724,30 @@ static void cqhci_error_irq(struct mmc_host *mmc, u32 status, int cmd_error, } } + /* + * Handle ICCE ("Invalid Crypto Configuration Error"). This should + * never happen, since the block layer ensures that all crypto-enabled + * I/O requests have a valid keyslot before they reach the driver. + * + * Note that GCE ("General Crypto Error") is different; it already got + * handled above by checking TERRI. + */ + if (status & CQHCI_IS_ICCE) { + tdpe = cqhci_readl(cq_host, CQHCI_TDPE); + WARN_ONCE(1, + "%s: cqhci: invalid crypto configuration error. IRQ status: 0x%08x TDPE: 0x%08x\n", + mmc_hostname(mmc), status, tdpe); + while (tdpe != 0) { + tag = __ffs(tdpe); + tdpe &= ~(1 << tag); + slot = &cq_host->slot[tag]; + if (!slot->mrq) + continue; + slot->flags = cqhci_error_flags(data_error, cmd_error); + cqhci_recovery_needed(mmc, slot->mrq, true); + } + } + if (!cq_host->recovery_halt) { /* * The only way to guarantee forward progress is to mark at @@ -784,7 +813,8 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, pr_debug("%s: cqhci: IRQ status: 0x%08x\n", mmc_hostname(mmc), status); - if ((status & CQHCI_IS_RED) || cmd_error || data_error) + if ((status & (CQHCI_IS_RED | CQHCI_IS_GCE | CQHCI_IS_ICCE)) || + cmd_error || data_error) cqhci_error_irq(mmc, status, cmd_error, data_error); if (status & CQHCI_IS_TCC) { @@ -1151,6 +1181,13 @@ int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, goto out_err; } + err = cqhci_crypto_init(cq_host); + if (err) { + pr_err("%s: CQHCI crypto initialization failed\n", + mmc_hostname(mmc)); + goto out_err; + } + spin_lock_init(&cq_host->lock); init_completion(&cq_host->halt_comp); |