From cd86102b66a52cf11ea05e457b7cdbdccd37557c Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Wed, 29 Jan 2020 16:16:18 +0530 Subject: [PATCH] mmc: cqhci: Add inline crypto support to cqhci Wire up cqhci.c with the eMMC Crypto API and support for block layer inline encryption additions and the keyslot manager. Ported and fixed the merged conflicts in cqhci.c file Added new member in cqhci_host to get platform device from sdhci during cqhci_pltfm_init(). (cherry picked from mainline kernel_msm-4.19 commit 2543833e). Conflicts: drivers/mmc/host/cqhci.c Test: 1. Device booted upto UI with File Based Encryption enabled. 2. Key insertion using fscryptctl tool. 3. Created new files under /data and checked retention across multiple re-boots. 4. vts_kernel_encryption_test tests. 5. check_encryption test for verifying metadata encryption. Change-Id: I6860cd29d6f044f559385d438048b850faf9a8be Signed-off-by: Neeraj Soni Signed-off-by: Vaibhav Agrawal --- drivers/mmc/host/cqhci.c | 77 +++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/cqhci.h | 25 +++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c index d97a9041fdd9..e7b6b995f5a3 100644 --- a/drivers/mmc/host/cqhci.c +++ b/drivers/mmc/host/cqhci.c @@ -18,6 +18,7 @@ #include #include "cqhci.h" +#include "cqhci-crypto.h" #define DCMD_SLOT 31 #define NUM_SLOTS 32 @@ -138,6 +139,8 @@ static void cqhci_dumpregs(struct cqhci_host *cq_host) cqhci_readl(cq_host, CQHCI_CRI), cqhci_readl(cq_host, CQHCI_CRA)); + cqhci_crypto_debug(cq_host); + if (cq_host->ops->dumpregs) cq_host->ops->dumpregs(mmc); else @@ -258,6 +261,11 @@ static void __cqhci_enable(struct cqhci_host *cq_host) if (cq_host->caps & CQHCI_TASK_DESC_SZ_128) cqcfg |= CQHCI_TASK_DESC_SZ; + if (cqhci_host_is_crypto_supported(cq_host)) { + cqhci_crypto_enable(cq_host); + cqcfg |= CQHCI_ICE_ENABLE; + } + cqhci_writel(cq_host, cqcfg, CQHCI_CFG); cqhci_writel(cq_host, lower_32_bits(cq_host->desc_dma_base), @@ -290,6 +298,9 @@ static void __cqhci_disable(struct cqhci_host *cq_host) { u32 cqcfg; + if (cqhci_host_is_crypto_supported(cq_host)) + cqhci_crypto_disable(cq_host); + cqcfg = cqhci_readl(cq_host, CQHCI_CFG); cqcfg &= ~CQHCI_ENABLE; cqhci_writel(cq_host, cqcfg, CQHCI_CFG); @@ -303,6 +314,8 @@ int cqhci_deactivate(struct mmc_host *mmc) { struct cqhci_host *cq_host = mmc->cqe_private; + cqhci_crypto_suspend(cq_host); + if (cq_host->enabled && cq_host->activated) __cqhci_disable(cq_host); @@ -561,6 +574,30 @@ static inline int cqhci_tag(struct mmc_request *mrq) return mrq->cmd ? DCMD_SLOT : mrq->tag; } +static inline +void cqhci_prep_crypto_desc(struct cqhci_host *cq_host, u64 *task_desc, + u64 ice_ctx) +{ + __le64 *ice_desc = NULL; + + if (cq_host->caps & CQHCI_CAP_CRYPTO_SUPPORT) { + /* + * Get the address of ice context for the given task descriptor. + * ice context is present in the upper 64bits of task descriptor + * ice_conext_base_address = task_desc + 8-bytes + */ + ice_desc = (__le64 *)((u8 *)task_desc + + CQHCI_TASK_DESC_ICE_PARAM_OFFSET); + memset(ice_desc, 0, CQHCI_TASK_DESC_ICE_PARAMS_SIZE); + + /* + * Assign upper 64bits data of task descritor with ice context + */ + if (ice_ctx) + *ice_desc = cpu_to_le64(ice_ctx); + } +} + static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq) { int err = 0; @@ -569,6 +606,7 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq) int tag = cqhci_tag(mrq); struct cqhci_host *cq_host = mmc->cqe_private; unsigned long flags; + u64 ice_ctx = 0; if (!cq_host->enabled) { pr_err("%s: cqhci: not enabled\n", mmc_hostname(mmc)); @@ -592,9 +630,17 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq) } if (mrq->data) { + err = cqhci_crypto_get_ctx(cq_host, mrq, &ice_ctx); + if (err) { + pr_err("%s: failed to retrieve crypto ctx for tag %d\n", + mmc_hostname(mmc), tag); + goto out; + } task_desc = (__le64 __force *)get_desc(cq_host, tag); cqhci_prep_task_desc(mrq, &data, 1); *task_desc = cpu_to_le64(data); + cqhci_prep_crypto_desc(cq_host, task_desc, ice_ctx); + err = cqhci_prep_tran_desc(mrq, cq_host, tag); if (err) { pr_err("%s: cqhci: failed to setup tx desc: %d\n", @@ -628,6 +674,9 @@ out_unlock: if (err) cqhci_post_req(mmc, mrq); + if (mrq->data) + cqhci_complete_crypto_desc(cq_host, mrq, NULL); +out: return err; } @@ -635,7 +684,15 @@ out_unlock: static void cqhci_crypto_update_queue(struct mmc_host *mmc, struct request_queue *queue) { - //struct cqhci_host *cq_host = mmc->cqe_private; + struct cqhci_host *cq_host = mmc->cqe_private; + + if (cq_host->caps & CQHCI_CAP_CRYPTO_SUPPORT) { + if (queue) + cqhci_crypto_setup_rq_keyslot_manager(cq_host, queue); + else + pr_err("%s can not register keyslot manager\n", + mmc_hostname(mmc)); + } } #endif @@ -755,6 +812,8 @@ static void cqhci_finish_mrq(struct mmc_host *mmc, unsigned int tag) data = mrq->data; if (data) { + cqhci_complete_crypto_desc(cq_host, mrq, NULL); + if (data->error) data->bytes_xfered = 0; else @@ -942,6 +1001,8 @@ static void cqhci_recovery_start(struct mmc_host *mmc) pr_debug("%s: cqhci: %s\n", mmc_hostname(mmc), __func__); + cqhci_crypto_reset(cq_host); + WARN_ON(!cq_host->recovery_halt); cqhci_halt(mmc, CQHCI_START_HALT_TIMEOUT); @@ -1062,6 +1123,8 @@ static void cqhci_recovery_finish(struct mmc_host *mmc) cqhci_set_irqs(cq_host, CQHCI_IS_MASK); + cqhci_crypto_recovery_finish(cq_host); + pr_debug("%s: cqhci: recovery done\n", mmc_hostname(mmc)); } @@ -1103,6 +1166,11 @@ struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev) dev_err(&pdev->dev, "failed to remap cqhci regs\n"); return ERR_PTR(-EBUSY); } + +#ifdef CONFIG_MMC_CQHCI_CRYPTO_QTI + cq_host->pdev = pdev; +#endif /* CONFIG_MMC_CQHCI_CRYPTO_QTI */ + dev_dbg(&pdev->dev, "CMDQ ioremap: done\n"); return cq_host; @@ -1148,6 +1216,13 @@ int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, spin_lock_init(&cq_host->lock); + err = cqhci_host_init_crypto(cq_host); + if (err) { + pr_err("%s: CQHCI version %u.%02u Crypto init failed err %d\n", + mmc_hostname(mmc), cqhci_ver_major(cq_host), + cqhci_ver_minor(cq_host), err); + } + init_completion(&cq_host->halt_comp); init_waitqueue_head(&cq_host->wait_queue); diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 0f9806212ee0..7a9b6d00a36c 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -32,6 +32,7 @@ #define CQHCI_DCMD 0x00001000 #define CQHCI_TASK_DESC_SZ 0x00000100 #define CQHCI_ENABLE 0x00000001 +#define CQHCI_ICE_ENABLE 0x00000002 /* control */ #define CQHCI_CTL 0x0C @@ -148,11 +149,20 @@ #define CQHCI_DAT_LENGTH(x) (((x) & 0xFFFF) << 16) #define CQHCI_DAT_ADDR_LO(x) (((x) & 0xFFFFFFFF) << 32) #define CQHCI_DAT_ADDR_HI(x) (((x) & 0xFFFFFFFF) << 0) +#define DATA_UNIT_NUM(x) (((u64)(x) & 0xFFFFFFFF) << 0) +#define CRYPTO_CONFIG_INDEX(x) (((u64)(x) & 0xFF) << 32) +#define CRYPTO_ENABLE(x) (((u64)(x) & 0x1) << 47) + +/* ICE context is present in the upper 64bits of task descriptor */ +#define CQHCI_TASK_DESC_ICE_PARAM_OFFSET 8 +/* ICE descriptor size */ +#define CQHCI_TASK_DESC_ICE_PARAMS_SIZE 8 struct cqhci_host_ops; struct mmc_host; struct mmc_request; struct cqhci_slot; +struct cqhci_host; /* CCAP - Crypto Capability 100h */ union cqhci_crypto_capabilities { @@ -240,6 +250,7 @@ struct cqhci_host_crypto_variant_ops { struct cqhci_host { const struct cqhci_host_ops *ops; void __iomem *mmio; + void __iomem *icemmio; struct mmc_host *mmc; spinlock_t lock; @@ -255,6 +266,7 @@ struct cqhci_host { u32 dcmd_slot; u32 caps; #define CQHCI_TASK_DESC_SZ_128 0x1 +#define CQHCI_CAP_CRYPTO_SUPPORT 0x2 u32 quirks; #define CQHCI_QUIRK_SHORT_TXFR_DESC_SZ 0x1 @@ -291,6 +303,19 @@ struct cqhci_host { struct completion halt_comp; wait_queue_head_t wait_queue; struct cqhci_slot *slot; + const struct cqhci_host_crypto_variant_ops *crypto_vops; + +#ifdef CONFIG_MMC_CQHCI_CRYPTO + union cqhci_crypto_capabilities crypto_capabilities; + union cqhci_crypto_cap_entry *crypto_cap_array; + u32 crypto_cfg_register; +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct keyslot_manager *ksm; +#endif /* CONFIG_BLK_INLINE_ENCRYPTION */ +#endif /* CONFIG_MMC_CQHCI_CRYPTO */ +#ifdef CONFIG_MMC_CQHCI_CRYPTO_QTI + struct platform_device *pdev; +#endif /* CONFIG_MMC_CQHCI_CRYPTO_QTI */ }; struct cqhci_host_ops {