Message ID | 20201112194011.103774-5-ebiggers@kernel.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | eMMC inline encryption support | expand |
On 12/11/20 9:40 pm, Eric Biggers wrote: > From: Eric Biggers <ebiggers@google.com> > > On Snapdragon SoCs, the Linux kernel isn't permitted to directly access > the standard CQHCI crypto configuration registers. Instead, programming > and evicting keys must be done through vendor-specific SMC calls. > > To support this hardware, add a ->program_key() method to > 'struct cqhci_host_ops'. This allows overriding the standard CQHCI > crypto key programming / eviction procedure. > > This is inspired by the corresponding UFS crypto support, which uses > these same SMC calls. See commit 1bc726e26ef3 ("scsi: ufs: Add > program_key() variant op"). > > Signed-off-by: Eric Biggers <ebiggers@google.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> > --- > drivers/mmc/host/cqhci-crypto.c | 22 +++++++++++++--------- > drivers/mmc/host/cqhci.h | 4 ++++ > 2 files changed, 17 insertions(+), 9 deletions(-) > > diff --git a/drivers/mmc/host/cqhci-crypto.c b/drivers/mmc/host/cqhci-crypto.c > index b14a5a15f5b52..5e3488c19f70e 100644 > --- a/drivers/mmc/host/cqhci-crypto.c > +++ b/drivers/mmc/host/cqhci-crypto.c > @@ -30,13 +30,16 @@ cqhci_host_from_ksm(struct blk_keyslot_manager *ksm) > return mmc->cqe_private; > } > > -static void cqhci_crypto_program_key(struct cqhci_host *cq_host, > - const union cqhci_crypto_cfg_entry *cfg, > - int slot) > +static int 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])); > > @@ -51,6 +54,7 @@ static void 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_keyslot_manager *ksm, > @@ -67,6 +71,7 @@ static int cqhci_crypto_keyslot_program(struct blk_keyslot_manager *ksm, > 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++) { > @@ -93,13 +98,13 @@ static int cqhci_crypto_keyslot_program(struct blk_keyslot_manager *ksm, > memcpy(cfg.crypto_key, key->raw, key->size); > } > > - cqhci_crypto_program_key(cq_host, &cfg, slot); > + err = cqhci_crypto_program_key(cq_host, &cfg, slot); > > memzero_explicit(&cfg, sizeof(cfg)); > - return 0; > + return err; > } > > -static void cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot) > +static int cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot) > { > /* > * Clear the crypto cfg on the device. Clearing CFGE > @@ -107,7 +112,7 @@ static void cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot) > */ > union cqhci_crypto_cfg_entry cfg = {}; > > - cqhci_crypto_program_key(cq_host, &cfg, slot); > + return cqhci_crypto_program_key(cq_host, &cfg, slot); > } > > static int cqhci_crypto_keyslot_evict(struct blk_keyslot_manager *ksm, > @@ -116,8 +121,7 @@ static int cqhci_crypto_keyslot_evict(struct blk_keyslot_manager *ksm, > { > struct cqhci_host *cq_host = cqhci_host_from_ksm(ksm); > > - cqhci_crypto_clear_keyslot(cq_host, slot); > - return 0; > + return cqhci_crypto_clear_keyslot(cq_host, slot); > } > > static const struct blk_ksm_ll_ops cqhci_ksm_ops = { > diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h > index 5c18734624fea..ece997dd8bcc7 100644 > --- a/drivers/mmc/host/cqhci.h > +++ b/drivers/mmc/host/cqhci.h > @@ -287,6 +287,10 @@ 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 > }; > > static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) >
diff --git a/drivers/mmc/host/cqhci-crypto.c b/drivers/mmc/host/cqhci-crypto.c index b14a5a15f5b52..5e3488c19f70e 100644 --- a/drivers/mmc/host/cqhci-crypto.c +++ b/drivers/mmc/host/cqhci-crypto.c @@ -30,13 +30,16 @@ cqhci_host_from_ksm(struct blk_keyslot_manager *ksm) return mmc->cqe_private; } -static void cqhci_crypto_program_key(struct cqhci_host *cq_host, - const union cqhci_crypto_cfg_entry *cfg, - int slot) +static int 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])); @@ -51,6 +54,7 @@ static void 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_keyslot_manager *ksm, @@ -67,6 +71,7 @@ static int cqhci_crypto_keyslot_program(struct blk_keyslot_manager *ksm, 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++) { @@ -93,13 +98,13 @@ static int cqhci_crypto_keyslot_program(struct blk_keyslot_manager *ksm, memcpy(cfg.crypto_key, key->raw, key->size); } - cqhci_crypto_program_key(cq_host, &cfg, slot); + err = cqhci_crypto_program_key(cq_host, &cfg, slot); memzero_explicit(&cfg, sizeof(cfg)); - return 0; + return err; } -static void cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot) +static int cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot) { /* * Clear the crypto cfg on the device. Clearing CFGE @@ -107,7 +112,7 @@ static void cqhci_crypto_clear_keyslot(struct cqhci_host *cq_host, int slot) */ union cqhci_crypto_cfg_entry cfg = {}; - cqhci_crypto_program_key(cq_host, &cfg, slot); + return cqhci_crypto_program_key(cq_host, &cfg, slot); } static int cqhci_crypto_keyslot_evict(struct blk_keyslot_manager *ksm, @@ -116,8 +121,7 @@ static int cqhci_crypto_keyslot_evict(struct blk_keyslot_manager *ksm, { struct cqhci_host *cq_host = cqhci_host_from_ksm(ksm); - cqhci_crypto_clear_keyslot(cq_host, slot); - return 0; + return cqhci_crypto_clear_keyslot(cq_host, slot); } static const struct blk_ksm_ll_ops cqhci_ksm_ops = { diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 5c18734624fea..ece997dd8bcc7 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -287,6 +287,10 @@ 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 }; static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)