diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-msm.c')
-rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 115 |
1 files changed, 91 insertions, 24 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 1fcaaf683d68..bc6ca49652f8 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1564,6 +1564,7 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_host *mmc = host->mmc; bool done = false; u32 val = SWITCHABLE_SIGNALING_VOLTAGE; const struct sdhci_msm_offset *msm_offset = @@ -1621,6 +1622,12 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) "%s: pwr_irq for req: (%d) timed out\n", mmc_hostname(host->mmc), req_type); } + + if ((req_type & REQ_BUS_ON) && mmc->card && !mmc->ops->get_cd(mmc)) { + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + host->pwr = 0; + } + pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc), __func__, req_type); } @@ -1679,6 +1686,13 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) udelay(10); } + if ((irq_status & CORE_PWRCTL_BUS_ON) && mmc->card && + !mmc->ops->get_cd(mmc)) { + msm_host_writel(msm_host, CORE_PWRCTL_BUS_FAIL, host, + msm_offset->core_pwrctl_ctl); + return; + } + /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { pwr_state = REQ_BUS_ON; @@ -1856,17 +1870,24 @@ 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; - ice = of_qcom_ice_get(dev); + ice = devm_of_qcom_ice_get(dev); if (ice == ERR_PTR(-EOPNOTSUPP)) { dev_warn(dev, "Disabling inline encryption support\n"); ice = NULL; @@ -1875,9 +1896,44 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, if (IS_ERR_OR_NULL(ice)) return PTR_ERR_OR_ZERO(ice); + if (qcom_ice_get_supported_key_type(ice) != BLK_CRYPTO_KEY_TYPE_RAW) { + dev_warn(dev, "Wrapped keys not supported. Disabling inline encryption support.\n"); + return 0; + } + 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->key_types_supported = BLK_CRYPTO_KEY_TYPE_RAW; + 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; } @@ -1903,35 +1959,46 @@ 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; +} - /* 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; +/* + * 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); - 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); + return qcom_ice_program_key(msm_host->ice, slot, key); } +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, @@ -2037,7 +2104,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 }; |