Commit 741521fa authored by Eric Biggers's avatar Eric Biggers Committed by Ulf Hansson
Browse files

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: default avatarEric Biggers <ebiggers@google.com>
Message-ID: <20241213041958.202565-8-ebiggers@kernel.org>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 08a7ead3
Loading
Loading
Loading
Loading
+16 −17
Original line number Diff line number Diff line
@@ -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,
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;
+3 −5
Original line number Diff line number Diff line
@@ -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)
+75 −19
Original line number Diff line number Diff line
@@ -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
};