mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 22:52:19 +02:00
mmc: sdhci-msm: convert to use custom crypto profile
As is being done in ufs-qcom, make the sdhci-msm driver override the full crypto profile rather than "just" key programming and eviction. This makes it much more straightforward to add support for hardware-wrapped inline encryption keys. It also makes it easy to pass the original blk_crypto_key down to qcom_ice_program_key() once it is updated to require the key in that form. Signed-off-by: Eric Biggers <ebiggers@google.com> Message-ID: <20241213041958.202565-8-ebiggers@kernel.org> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
08a7ead324
commit
741521fa27
|
|
@ -28,16 +28,13 @@ cqhci_host_from_crypto_profile(struct blk_crypto_profile *profile)
|
|||
return mmc_from_crypto_profile(profile)->cqe_private;
|
||||
}
|
||||
|
||||
static int cqhci_crypto_program_key(struct cqhci_host *cq_host,
|
||||
const union cqhci_crypto_cfg_entry *cfg,
|
||||
int slot)
|
||||
static void cqhci_crypto_program_key(struct cqhci_host *cq_host,
|
||||
const union cqhci_crypto_cfg_entry *cfg,
|
||||
int slot)
|
||||
{
|
||||
u32 slot_offset = cq_host->crypto_cfg_register + slot * sizeof(*cfg);
|
||||
int i;
|
||||
|
||||
if (cq_host->ops->program_key)
|
||||
return cq_host->ops->program_key(cq_host, cfg, slot);
|
||||
|
||||
/* Clear CFGE */
|
||||
cqhci_writel(cq_host, 0, slot_offset + 16 * sizeof(cfg->reg_val[0]));
|
||||
|
||||
|
|
@ -52,7 +49,6 @@ static int cqhci_crypto_program_key(struct cqhci_host *cq_host,
|
|||
/* Write dword 16, which includes the new value of CFGE */
|
||||
cqhci_writel(cq_host, le32_to_cpu(cfg->reg_val[16]),
|
||||
slot_offset + 16 * sizeof(cfg->reg_val[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cqhci_crypto_keyslot_program(struct blk_crypto_profile *profile,
|
||||
|
|
@ -69,7 +65,6 @@ static int cqhci_crypto_keyslot_program(struct blk_crypto_profile *profile,
|
|||
int i;
|
||||
int cap_idx = -1;
|
||||
union cqhci_crypto_cfg_entry cfg = {};
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(CQHCI_CRYPTO_KEY_SIZE_INVALID != 0);
|
||||
for (i = 0; i < cq_host->crypto_capabilities.num_crypto_cap; i++) {
|
||||
|
|
@ -96,10 +91,10 @@ static int cqhci_crypto_keyslot_program(struct blk_crypto_profile *profile,
|
|||
memcpy(cfg.crypto_key, key->raw, key->size);
|
||||
}
|
||||
|
||||
err = cqhci_crypto_program_key(cq_host, &cfg, slot);
|
||||
cqhci_crypto_program_key(cq_host, &cfg, slot);
|
||||
|
||||
memzero_explicit(&cfg, sizeof(cfg));
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot)
|
||||
|
|
@ -110,7 +105,8 @@ static int cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot)
|
|||
*/
|
||||
union cqhci_crypto_cfg_entry cfg = {};
|
||||
|
||||
return cqhci_crypto_program_key(cq_host, &cfg, slot);
|
||||
cqhci_crypto_program_key(cq_host, &cfg, slot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cqhci_crypto_keyslot_evict(struct blk_crypto_profile *profile,
|
||||
|
|
@ -167,7 +163,6 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
|
|||
struct mmc_host *mmc = cq_host->mmc;
|
||||
struct device *dev = mmc_dev(mmc);
|
||||
struct blk_crypto_profile *profile = &mmc->crypto_profile;
|
||||
unsigned int num_keyslots;
|
||||
unsigned int cap_idx;
|
||||
enum blk_crypto_mode_num blk_mode_num;
|
||||
unsigned int slot;
|
||||
|
|
@ -177,6 +172,9 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
|
|||
!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS))
|
||||
goto out;
|
||||
|
||||
if (cq_host->ops->uses_custom_crypto_profile)
|
||||
goto profile_initialized;
|
||||
|
||||
cq_host->crypto_capabilities.reg_val =
|
||||
cpu_to_le32(cqhci_readl(cq_host, CQHCI_CCAP));
|
||||
|
||||
|
|
@ -195,9 +193,8 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
|
|||
* 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_crypto_profile_init(dev, profile, num_keyslots);
|
||||
err = devm_blk_crypto_profile_init(
|
||||
dev, profile, cq_host->crypto_capabilities.config_count + 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
|
@ -225,9 +222,11 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
|
|||
cq_host->crypto_cap_array[cap_idx].sdus_mask * 512;
|
||||
}
|
||||
|
||||
profile_initialized:
|
||||
|
||||
/* 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);
|
||||
for (slot = 0; slot < profile->num_slots; slot++)
|
||||
profile->ll_ops.keyslot_evict(profile, NULL, slot);
|
||||
|
||||
/* CQHCI crypto requires the use of 128-bit task descriptors. */
|
||||
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
|
||||
|
|
|
|||
|
|
@ -289,13 +289,11 @@ struct cqhci_host_ops {
|
|||
u64 *data);
|
||||
void (*pre_enable)(struct mmc_host *mmc);
|
||||
void (*post_disable)(struct mmc_host *mmc);
|
||||
#ifdef CONFIG_MMC_CRYPTO
|
||||
int (*program_key)(struct cqhci_host *cq_host,
|
||||
const union cqhci_crypto_cfg_entry *cfg, int slot);
|
||||
#endif
|
||||
void (*set_tran_desc)(struct cqhci_host *cq_host, u8 **desc,
|
||||
dma_addr_t addr, int len, bool end, bool dma64);
|
||||
|
||||
#ifdef CONFIG_MMC_CRYPTO
|
||||
bool uses_custom_crypto_profile;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)
|
||||
|
|
|
|||
|
|
@ -1807,12 +1807,19 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||
|
||||
#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;
|
||||
|
|
@ -1827,8 +1834,37 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
|
|||
return PTR_ERR_OR_ZERO(ice);
|
||||
|
||||
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->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;
|
||||
}
|
||||
|
||||
|
|
@ -1854,35 +1890,55 @@ 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* 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;
|
||||
if (key->crypto_cfg.crypto_mode != BLK_ENCRYPTION_MODE_AES_256_XTS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
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);
|
||||
key->raw,
|
||||
key->crypto_cfg.data_unit_size / 512,
|
||||
slot);
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
@ -1988,7 +2044,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
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user