Re: [PATCH v5 4/9] mmc: cqhci: add support for inline encryption

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 21 Jan 2021 at 10:03, Eric Biggers <ebiggers@xxxxxxxxxx> wrote:
>
> From: Eric Biggers <ebiggers@xxxxxxxxxx>
>
> Add support for eMMC inline encryption using the blk-crypto framework
> (Documentation/block/inline-encryption.rst).
>
> eMMC inline encryption support is specified by the upcoming JEDEC eMMC
> v5.2 specification.  It is only specified for the CQ interface, not the
> non-CQ interface.  Although the eMMC v5.2 specification hasn't been
> officially released yet, the crypto support was already agreed on
> several years ago, and it was already implemented by at least two major
> hardware vendors.  Lots of hardware in the field already supports and
> uses it, e.g. Snapdragon 630 to give one example.
>
> eMMC inline encryption support is very similar to the UFS inline
> encryption support which was standardized in the UFS v2.1 specification
> and was already upstreamed.  The only major difference is that eMMC
> limits data unit numbers to 32 bits, unlike UFS's 64 bits.
>
> Like we did with UFS, make the crypto support opt-in by individual
> drivers; don't enable it automatically whenever the hardware declares
> crypto support.  This is necessary because in every case we've seen,
> some extra vendor-specific logic is needed to use the crypto support.
>
> Co-developed-by: Satya Tangirala <satyat@xxxxxxxxxx>
> Signed-off-by: Satya Tangirala <satyat@xxxxxxxxxx>
> Acked-by: Adrian Hunter <adrian.hunter@xxxxxxxxx>
> Reviewed-by: Satya Tangirala <satyat@xxxxxxxxxx>
> Reviewed-and-tested-by: Peng Zhou <peng.zhou@xxxxxxxxxxxx>
> Signed-off-by: Eric Biggers <ebiggers@xxxxxxxxxx>
> ---

[...]

> +/**
> + * cqhci_crypto_init - initialize CQHCI crypto support
> + * @cq_host: a cqhci host
> + *
> + * If the driver previously set MMC_CAP2_CRYPTO and the CQE declares
> + * CQHCI_CAP_CS, initialize the crypto support.  This involves reading the
> + * crypto capability registers, initializing the keyslot manager, clearing all
> + * keyslots, and enabling 128-bit task descriptors.
> + *
> + * Return: 0 if crypto was initialized or isn't supported; whether
> + *        MMC_CAP2_CRYPTO remains set indicates which one of those cases it is.
> + *        Also can return a negative errno value on unexpected error.
> + */
> +int cqhci_crypto_init(struct cqhci_host *cq_host)
> +{
> +       struct mmc_host *mmc = cq_host->mmc;
> +       struct device *dev = mmc_dev(mmc);
> +       struct blk_keyslot_manager *ksm = &mmc->ksm;
> +       unsigned int num_keyslots;
> +       unsigned int cap_idx;
> +       enum blk_crypto_mode_num blk_mode_num;
> +       unsigned int slot;
> +       int err = 0;
> +
> +       if (!(mmc->caps2 & MMC_CAP2_CRYPTO) ||
> +           !(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS))
> +               goto out;
> +
> +       cq_host->crypto_capabilities.reg_val =
> +                       cpu_to_le32(cqhci_readl(cq_host, CQHCI_CCAP));
> +
> +       cq_host->crypto_cfg_register =
> +               (u32)cq_host->crypto_capabilities.config_array_ptr * 0x100;
> +
> +       cq_host->crypto_cap_array =
> +               devm_kcalloc(dev, cq_host->crypto_capabilities.num_crypto_cap,
> +                            sizeof(cq_host->crypto_cap_array[0]), GFP_KERNEL);
> +       if (!cq_host->crypto_cap_array) {
> +               err = -ENOMEM;
> +               goto out;
> +       }
> +
> +       /*
> +        * 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_ksm_init(dev, ksm, num_keyslots);
> +       if (err)
> +               goto out;
> +
> +       ksm->ksm_ll_ops = cqhci_ksm_ops;
> +       ksm->dev = dev;
> +
> +       /* Unfortunately, CQHCI crypto only supports 32 DUN bits. */
> +       ksm->max_dun_bytes_supported = 4;
> +
> +       /*
> +        * Cache all the crypto capabilities and advertise the supported crypto
> +        * modes and data unit sizes to the block layer.
> +        */
> +       for (cap_idx = 0; cap_idx < cq_host->crypto_capabilities.num_crypto_cap;
> +            cap_idx++) {
> +               cq_host->crypto_cap_array[cap_idx].reg_val =
> +                       cpu_to_le32(cqhci_readl(cq_host,
> +                                               CQHCI_CRYPTOCAP +
> +                                               cap_idx * sizeof(__le32)));
> +               blk_mode_num = cqhci_find_blk_crypto_mode(
> +                                       cq_host->crypto_cap_array[cap_idx]);
> +               if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID)
> +                       continue;
> +               ksm->crypto_modes_supported[blk_mode_num] |=
> +                       cq_host->crypto_cap_array[cap_idx].sdus_mask * 512;
> +       }
> +
> +       /* 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);
> +
> +       /* CQHCI crypto requires the use of 128-bit task descriptors. */
> +       cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
> +
> +       return 0;
> +
> +out:
> +       mmc->caps2 &= ~MMC_CAP2_CRYPTO;
> +       return err;
> +}
> diff --git a/drivers/mmc/host/cqhci-crypto.h b/drivers/mmc/host/cqhci-crypto.h
> new file mode 100644
> index 0000000000000..60b58ee0e6256
> --- /dev/null
> +++ b/drivers/mmc/host/cqhci-crypto.h
> @@ -0,0 +1,47 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * CQHCI crypto engine (inline encryption) support
> + *
> + * Copyright 2020 Google LLC
> + */
> +
> +#ifndef LINUX_MMC_CQHCI_CRYPTO_H
> +#define LINUX_MMC_CQHCI_CRYPTO_H
> +
> +#include <linux/mmc/host.h>
> +
> +#include "cqhci.h"
> +
> +#ifdef CONFIG_MMC_CRYPTO
> +
> +int cqhci_crypto_init(struct cqhci_host *host);
> +
> +/*
> + * Returns the crypto bits that should be set in bits 64-127 of the
> + * task descriptor.
> + */
> +static inline u64 cqhci_crypto_prep_task_desc(struct mmc_request *mrq)
> +{
> +       if (!mrq->crypto_enabled)
> +               return 0;
> +
> +       return CQHCI_CRYPTO_ENABLE_BIT |
> +              CQHCI_CRYPTO_KEYSLOT(mrq->crypto_key_slot) |
> +              mrq->data_unit_num;
> +}
> +
> +#else /* CONFIG_MMC_CRYPTO */
> +
> +static inline int cqhci_crypto_init(struct cqhci_host *host)
> +{
> +       return 0;

The host calling this function may have MMC_CAP2_CRYPTO set for it.

When CONFIG_MMC_CRYPTO is set, cqhci_crypto_init() may unset
MMC_CAP2_CRYPTO if initialization fails. It seems like we should unset
MMC_CAP2_CRYPTO in this stub function as well, right?

> +}
> +
> +static inline u64 cqhci_crypto_prep_task_desc(struct mmc_request *mrq)
> +{
> +       return 0;
> +}
> +
> +#endif /* !CONFIG_MMC_CRYPTO */
> +
> +#endif /* LINUX_MMC_CQHCI_CRYPTO_H */

[...]

Kind regards
Uffe



[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux