diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/host/cmdq_hci.c | 46 | ||||
| -rw-r--r-- | drivers/mmc/host/cmdq_hci.h | 8 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm-ice.c | 211 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm-ice.h | 17 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 27 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h | 2 |
7 files changed, 260 insertions, 52 deletions
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index d712f29da9f1..a7546471e780 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -345,6 +345,7 @@ static int cmdq_enable(struct mmc_host *mmc) { int err = 0; u32 cqcfg; + u32 cqcap = 0; bool dcmd_enable; struct cmdq_host *cq_host = mmc_cmdq_private(mmc); @@ -373,6 +374,18 @@ static int cmdq_enable(struct mmc_host *mmc) cqcfg = ((cq_host->caps & CMDQ_TASK_DESC_SZ_128 ? CQ_TASK_DESC_SZ : 0) | (dcmd_enable ? CQ_DCMD : 0)); + cqcap = cmdq_readl(cq_host, CQCAP); + if (cqcap & CQCAP_CS) { + /* + * In case host controller supports cryptographic operations + * then, it uses 128bit task descriptor. Upper 64 bits of task + * descriptor would be used to pass crypto specific informaton. + */ + cq_host->caps |= CMDQ_CAP_CRYPTO_SUPPORT | + CMDQ_TASK_DESC_SZ_128; + cqcfg |= CQ_ICE_ENABLE; + } + cmdq_writel(cq_host, cqcfg, CQCFG); /* enable CQ_HOST */ cmdq_writel(cq_host, cmdq_readl(cq_host, CQCFG) | CQ_ENABLE, @@ -688,6 +701,30 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc, upper_32_bits(*task_desc)); } +static inline +void cmdq_prep_crypto_desc(struct cmdq_host *cq_host, u64 *task_desc, + u64 ice_ctx) +{ + u64 *ice_desc = NULL; + + if (cq_host->caps & CMDQ_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 __force *)((u8 *)task_desc + + CQ_TASK_DESC_TASK_PARAMS_SIZE); + memset(ice_desc, 0, CQ_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 void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -711,6 +748,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) u32 tag = mrq->cmdq_req->tag; struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); struct sdhci_host *host = mmc_priv(mmc); + u64 ice_ctx = 0; if (!cq_host->enabled) { pr_err("%s: CMDQ host not enabled yet !!!\n", @@ -730,7 +768,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) } if (cq_host->ops->crypto_cfg) { - err = cq_host->ops->crypto_cfg(mmc, mrq, tag); + err = cq_host->ops->crypto_cfg(mmc, mrq, tag, &ice_ctx); if (err) { pr_err("%s: failed to configure crypto: err %d tag %d\n", mmc_hostname(mmc), err, tag); @@ -743,6 +781,9 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) cmdq_prep_task_desc(mrq, &data, 1, (mrq->cmdq_req->cmdq_req_flags & QBR)); *task_desc = cpu_to_le64(data); + + cmdq_prep_crypto_desc(cq_host, task_desc, ice_ctx); + cmdq_log_task_desc_history(cq_host, *task_desc, false); err = cmdq_prep_tran_desc(mrq, cq_host, tag); @@ -787,7 +828,8 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG); cmdq_runtime_pm_put(cq_host); - if (cq_host->ops->crypto_cfg_reset) + if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && + cq_host->ops->crypto_cfg_reset) cq_host->ops->crypto_cfg_reset(mmc, tag); mrq->done(mrq); } diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h index e1cbb126f411..05c924ae0935 100644 --- a/drivers/mmc/host/cmdq_hci.h +++ b/drivers/mmc/host/cmdq_hci.h @@ -18,11 +18,13 @@ #define CQVER 0x00 /* capabilities */ #define CQCAP 0x04 +#define CQCAP_CS (1 << 28) /* configuration */ #define CQCFG 0x08 #define CQ_DCMD 0x00001000 #define CQ_TASK_DESC_SZ 0x00000100 #define CQ_ENABLE 0x00000001 +#define CQ_ICE_ENABLE 0x00000002 /* control */ #define CQCTL 0x0C @@ -144,6 +146,9 @@ #define CQ_VENDOR_CFG 0x100 #define CMDQ_SEND_STATUS_TRIGGER (1 << 31) +#define CQ_TASK_DESC_TASK_PARAMS_SIZE 8 +#define CQ_TASK_DESC_ICE_PARAMS_SIZE 8 + struct task_history { u64 task; bool is_dcmd; @@ -161,6 +166,7 @@ struct cmdq_host { u32 dcmd_slot; u32 caps; #define CMDQ_TASK_DESC_SZ_128 0x1 +#define CMDQ_CAP_CRYPTO_SUPPORT 0x2 u32 quirks; #define CMDQ_QUIRK_SHORT_TXFR_DESC_SZ 0x1 @@ -208,7 +214,7 @@ struct cmdq_host_ops { void (*enhanced_strobe_mask)(struct mmc_host *mmc, bool set); int (*reset)(struct mmc_host *mmc); int (*crypto_cfg)(struct mmc_host *mmc, struct mmc_request *mrq, - u32 slot); + u32 slot, u64 *ice_ctx); void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot); void (*post_cqe_halt)(struct mmc_host *mmc); }; diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index dc8d865cfabc..a6ef06aa6f1d 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -211,60 +211,47 @@ void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot) host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot); } -int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, - u32 slot) +static +int sdhci_msm_ice_get_cfg(struct sdhci_msm_host *msm_host, struct request *req, + unsigned int *bypass, short *key_index) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; int err = 0; struct ice_data_setting ice_set; - sector_t lba = 0; - unsigned int ctrl_info_val = 0; - unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS; - struct request *req; - if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - BUG_ON(!mrq); memset(&ice_set, 0, sizeof(struct ice_data_setting)); - req = mrq->req; - if (req) { - lba = req->__sector; - if (msm_host->ice.vops->config_start) { - err = msm_host->ice.vops->config_start( - msm_host->ice.pdev, - req, &ice_set, false); - if (err) { - pr_err("%s: ice config failed %d\n", - mmc_hostname(host->mmc), err); - return err; - } + if (msm_host->ice.vops->config_start) { + err = msm_host->ice.vops->config_start( + msm_host->ice.pdev, + req, &ice_set, false); + if (err) { + pr_err("%s: ice config failed %d\n", + mmc_hostname(msm_host->mmc), err); + return err; } - /* if writing data command */ - if (rq_data_dir(req) == WRITE) - bypass = ice_set.encr_bypass ? - SDHCI_MSM_ICE_ENABLE_BYPASS : - SDHCI_MSM_ICE_DISABLE_BYPASS; - /* if reading data command */ - else if (rq_data_dir(req) == READ) - bypass = ice_set.decr_bypass ? - SDHCI_MSM_ICE_ENABLE_BYPASS : - SDHCI_MSM_ICE_DISABLE_BYPASS; - pr_debug("%s: %s: slot %d encr_bypass %d bypass %d decr_bypass %d key_index %d\n", - mmc_hostname(host->mmc), - (rq_data_dir(req) == WRITE) ? "WRITE" : "READ", - slot, ice_set.encr_bypass, bypass, - ice_set.decr_bypass, - ice_set.crypto_data.key_index); } + /* if writing data command */ + if (rq_data_dir(req) == WRITE) + *bypass = ice_set.encr_bypass ? + SDHCI_MSM_ICE_ENABLE_BYPASS : + SDHCI_MSM_ICE_DISABLE_BYPASS; + /* if reading data command */ + else if (rq_data_dir(req) == READ) + *bypass = ice_set.decr_bypass ? + SDHCI_MSM_ICE_ENABLE_BYPASS : + SDHCI_MSM_ICE_DISABLE_BYPASS; + *key_index = ice_set.crypto_data.key_index; + return err; +} + +static +void sdhci_msm_ice_update_cfg(struct sdhci_host *host, u64 lba, + u32 slot, unsigned int bypass, short key_index) +{ + unsigned int ctrl_info_val = 0; /* Configure ICE index */ ctrl_info_val = - (ice_set.crypto_data.key_index & + (key_index & MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX) << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX; @@ -285,9 +272,145 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot); writel_relaxed(ctrl_info_val, host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot); + /* Ensure ICE registers are configured before issuing SDHCI request */ + mb(); +} +static inline +void sdhci_msm_ice_hci_update_cmdq_cfg(u64 dun, unsigned int bypass, + short key_index, u64 *ice_ctx) +{ + /* + * The naming convention got changed between ICE2.0 and ICE3.0 + * registers fields. Below is the equivalent names for + * ICE3.0 Vs ICE2.0: + * Data Unit Number(DUN) == Logical Base address(LBA) + * Crypto Configuration index (CCI) == Key Index + * Crypto Enable (CE) == !BYPASS + */ + if (ice_ctx) + *ice_ctx = DATA_UNIT_NUM(dun) | + CRYPTO_CONFIG_INDEX(key_index) | + CRYPTO_ENABLE(!bypass); +} + +static +void sdhci_msm_ice_hci_update_noncq_cfg(struct sdhci_host *host, + u64 dun, unsigned int bypass, short key_index) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + unsigned int crypto_params = 0; + /* + * The naming convention got changed between ICE2.0 and ICE3.0 + * registers fields. Below is the equivalent names for + * ICE3.0 Vs ICE2.0: + * Data Unit Number(DUN) == Logical Base address(LBA) + * Crypto Configuration index (CCI) == Key Index + * Crypto Enable (CE) == !BYPASS + */ + /* Configure ICE bypass mode */ + crypto_params |= + (!bypass & MASK_SDHCI_MSM_ICE_HCI_PARAM_CE) + << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE; + /* Configure Crypto Configure Index (CCI) */ + crypto_params |= (key_index & + MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI) + << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI; + + writel_relaxed((crypto_params & 0xFFFFFFFF), + msm_host->cryptoio + ICE_NONCQ_CRYPTO_PARAMS); + + /* Update DUN */ + writel_relaxed((dun & 0xFFFFFFFF), + msm_host->cryptoio + ICE_NONCQ_CRYPTO_DUN); /* Ensure ICE registers are configured before issuing SDHCI request */ mb(); +} + +int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, + u32 slot) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + int err = 0; + short key_index = 0; + sector_t lba = 0; + unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS; + struct request *req; + + if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { + pr_err("%s: ice is in invalid state %d\n", + mmc_hostname(host->mmc), msm_host->ice.state); + return -EINVAL; + } + + WARN_ON(!mrq); + if (!mrq) + return -EINVAL; + req = mrq->req; + if (req) { + lba = req->__sector; + err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index); + if (err) + return err; + pr_debug("%s: %s: slot %d bypass %d key_index %d\n", + mmc_hostname(host->mmc), + (rq_data_dir(req) == WRITE) ? "WRITE" : "READ", + slot, bypass, key_index); + } + + if (msm_host->ice_hci_support) { + /* For ICE HCI / ICE3.0 */ + sdhci_msm_ice_hci_update_noncq_cfg(host, lba, bypass, + key_index); + } else { + /* For ICE versions earlier to ICE3.0 */ + sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index); + } + return 0; +} + +int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, + struct mmc_request *mrq, u32 slot, u64 *ice_ctx) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + int err = 0; + short key_index; + sector_t lba = 0; + unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS; + struct request *req; + + if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { + pr_err("%s: ice is in invalid state %d\n", + mmc_hostname(host->mmc), msm_host->ice.state); + return -EINVAL; + } + + WARN_ON(!mrq); + if (!mrq) + return -EINVAL; + req = mrq->req; + if (req) { + lba = req->__sector; + err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index); + if (err) + return err; + pr_debug("%s: %s: slot %d bypass %d key_index %d\n", + mmc_hostname(host->mmc), + (rq_data_dir(req) == WRITE) ? "WRITE" : "READ", + slot, bypass, key_index); + } + + if (msm_host->ice_hci_support) { + /* For ICE HCI / ICE3.0 */ + sdhci_msm_ice_hci_update_cmdq_cfg(lba, bypass, key_index, + ice_ctx); + } else { + /* For ICE versions earlier to ICE3.0 */ + sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index); + } return 0; } diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h index 23922cf7458a..d8d640437522 100644 --- a/drivers/mmc/host/sdhci-msm-ice.h +++ b/drivers/mmc/host/sdhci-msm-ice.h @@ -42,6 +42,8 @@ #define ICE_HCI_SUPPORT (1 << 28) #define ICE_CQ_CONFIG 0x08 #define CRYPTO_GENERAL_ENABLE (1 << 1) +#define ICE_NONCQ_CRYPTO_PARAMS 0x70 +#define ICE_NONCQ_CRYPTO_DUN 0x74 /* ICE3.0 register which got added hc reg space */ #define HC_VENDOR_SPECIFIC_FUNC4 0x260 @@ -52,8 +54,10 @@ /* SDHCI MSM ICE CTRL Info register offset */ enum { OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0, - OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 0x1, - OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU = 0x6, + OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 1, + OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU = 6, + OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0, + OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE = 8, }; /* SDHCI MSM ICE CTRL Info register masks */ @@ -61,6 +65,8 @@ enum { MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0x1, MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 0x1F, MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU = 0x7, + MASK_SDHCI_MSM_ICE_HCI_PARAM_CE = 0x1, + MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0xff }; /* SDHCI MSM ICE encryption/decryption bypass state */ @@ -99,6 +105,8 @@ int sdhci_msm_ice_init(struct sdhci_host *host); void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot); int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, u32 slot); +int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, + struct mmc_request *mrq, u32 slot, u64 *ice_ctx); int sdhci_msm_ice_reset(struct sdhci_host *host); int sdhci_msm_ice_resume(struct sdhci_host *host); int sdhci_msm_ice_suspend(struct sdhci_host *host); @@ -130,6 +138,11 @@ inline int sdhci_msm_ice_cfg(struct sdhci_host *host, { return 0; } +inline int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, + struct mmc_request *mrq, u32 slot, u64 *ice_ctx) +{ + return 0; +} inline int sdhci_msm_ice_reset(struct sdhci_host *host) { return 0; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2e46cc8ddad9..f43f22503aa3 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -3997,6 +3997,7 @@ static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host) static struct sdhci_ops sdhci_msm_ops = { .crypto_engine_cfg = sdhci_msm_ice_cfg, + .crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg, .crypto_cfg_reset = sdhci_msm_ice_cfg_reset, .crypto_engine_reset = sdhci_msm_ice_reset, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3fd564388720..43853306a6bb 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3632,14 +3632,35 @@ static void sdhci_cmdq_clear_set_dumpregs(struct mmc_host *mmc, bool set) host->ops->clear_set_dumpregs(host, set); } static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc, - struct mmc_request *mrq, u32 slot) + struct mmc_request *mrq, u32 slot, u64 *ice_ctx) { struct sdhci_host *host = mmc_priv(mmc); + int err = 0; if (!host->is_crypto_en) return 0; - return sdhci_crypto_cfg(host, mrq, slot); + if (host->crypto_reset_reqd && host->ops->crypto_engine_reset) { + err = host->ops->crypto_engine_reset(host); + if (err) { + pr_err("%s: crypto reset failed\n", + mmc_hostname(host->mmc)); + goto out; + } + host->crypto_reset_reqd = false; + } + + if (host->ops->crypto_engine_cmdq_cfg) { + err = host->ops->crypto_engine_cmdq_cfg(host, mrq, + slot, ice_ctx); + if (err) { + pr_err("%s: failed to configure crypto\n", + mmc_hostname(host->mmc)); + goto out; + } + } +out: + return err; } static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot) @@ -3702,7 +3723,7 @@ static void sdhci_cmdq_clear_set_dumpregs(struct mmc_host *mmc, bool set) } static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc, - struct mmc_request *mrq, u32 slot) + struct mmc_request *mrq, u32 slot, u64 *ice_ctx) { return 0; } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e5419b42a444..c4bbdd80f29c 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -657,6 +657,8 @@ struct sdhci_ops { int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); int (*crypto_engine_cfg)(struct sdhci_host *host, struct mmc_request *mrq, u32 slot); + int (*crypto_engine_cmdq_cfg)(struct sdhci_host *host, + struct mmc_request *mrq, u32 slot, u64 *ice_ctx); int (*crypto_engine_reset)(struct sdhci_host *host); void (*crypto_cfg_reset)(struct sdhci_host *host, unsigned int slot); void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); |
