Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4e3acfb authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "defconfig: Support for QTI inline encryption"

parents 61c07846 368be07f
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -164,3 +164,6 @@ CONFIG_MMC_SDHCI_MSM=m
CONFIG_QCOM_KGSL=m
CONFIG_QCOM_KGSL=m
CONFIG_QCOM_QFPROM=m
CONFIG_QCOM_QFPROM=m
CONFIG_INTERCONNECT_TEST=m
CONFIG_INTERCONNECT_TEST=m
CONFIG_SCSI_UFS_CRYPTO_QTI=m
CONFIG_QTI_CRYPTO_COMMON=m
CONFIG_QTI_HW_KEY_MANAGER=m
+8 −0
Original line number Original line Diff line number Diff line
@@ -177,3 +177,11 @@ config SCSI_UFS_CRYPTO
	  Enabling this makes it possible for the kernel to use the crypto
	  Enabling this makes it possible for the kernel to use the crypto
	  capabilities of the UFS device (if present) to perform crypto
	  capabilities of the UFS device (if present) to perform crypto
	  operations on data being transferred to/from the device.
	  operations on data being transferred to/from the device.

config SCSI_UFS_CRYPTO_QTI
	tristate "Vendor specific UFS Crypto Engine Support"
	depends on SCSI_UFS_CRYPTO
	help
	 Enable Vendor Crypto Engine Support in UFS
	 Enabling this allows kernel to use UFS crypto operations defined
	 and implemented by QTI.
+2 −0
Original line number Original line Diff line number Diff line
@@ -16,3 +16,5 @@ ufshcd-qti-core-y += ufshcd-qti.o ufs-sysfs.o
ufshcd-qti-core-$(CONFIG_SCSI_UFS_BSG)	+= ufs_bsg.o
ufshcd-qti-core-$(CONFIG_SCSI_UFS_BSG)	+= ufs_bsg.o
ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o
ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o
ufshcd-qti-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o
ufshcd-qti-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o
ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO_QTI) += ufshcd-crypto-qti.o
ufshcd-qti-core-$(CONFIG_SCSI_UFS_CRYPTO_QTI) += ufshcd-crypto-qti.o
+8 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@
#include "ufs-qcom.h"
#include "ufs-qcom.h"
#include "ufshci.h"
#include "ufshci.h"
#include "ufs_quirks.h"
#include "ufs_quirks.h"
#include "ufshcd-crypto-qti.h"

#define UFS_QCOM_DEFAULT_DBG_PRINT_EN	\
#define UFS_QCOM_DEFAULT_DBG_PRINT_EN	\
	(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
	(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)


@@ -2149,6 +2151,12 @@ static int ufs_qcom_init(struct ufs_hba *hba)
		goto out_variant_clear;
		goto out_variant_clear;
	}
	}


	/*
	 * Set the vendor specific ops needed for ICE.
	 * Default implementation if the ops are not set.
	 */
	ufshcd_crypto_qti_set_vops(hba);

	err = ufs_qcom_bus_register(host);
	err = ufs_qcom_bus_register(host);
	if (err)
	if (err)
		goto out_variant_clear;
		goto out_variant_clear;
+297 −0
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * UFS Crypto ops QTI implementation.
 *
 * Copyright (c) 2020, Linux Foundation. All rights reserved.
 */

#include <crypto/algapi.h>
#include <linux/platform_device.h>
#include <linux/crypto-qti-common.h>

#include "ufshcd-crypto-qti.h"

#define MINIMUM_DUN_SIZE 512
#define MAXIMUM_DUN_SIZE 65536

#define NUM_KEYSLOTS(hba) (hba->crypto_capabilities.config_count + 1)

static struct ufs_hba_crypto_variant_ops ufshcd_crypto_qti_variant_ops = {
	.hba_init_crypto = ufshcd_crypto_qti_init_crypto,
	.enable = ufshcd_crypto_qti_enable,
	.disable = ufshcd_crypto_qti_disable,
	.resume = ufshcd_crypto_qti_resume,
	.debug = ufshcd_crypto_qti_debug,
};

static uint8_t get_data_unit_size_mask(unsigned int data_unit_size)
{
	if (data_unit_size < MINIMUM_DUN_SIZE ||
		data_unit_size > MAXIMUM_DUN_SIZE ||
	    !is_power_of_2(data_unit_size))
		return 0;

	return data_unit_size / MINIMUM_DUN_SIZE;
}

static bool ice_cap_idx_valid(struct ufs_hba *hba,
			      unsigned int cap_idx)
{
	return cap_idx < hba->crypto_capabilities.num_crypto_cap;
}

void ufshcd_crypto_qti_enable(struct ufs_hba *hba)
{
	int err = 0;

	if (!ufshcd_hba_is_crypto_supported(hba))
		return;

	err = crypto_qti_enable(hba->crypto_vops->priv);
	if (err) {
		pr_err("%s: Error enabling crypto, err %d\n",
				__func__, err);
		ufshcd_crypto_qti_disable(hba);
	}

	ufshcd_crypto_enable_spec(hba);

}

void ufshcd_crypto_qti_disable(struct ufs_hba *hba)
{
	ufshcd_crypto_disable_spec(hba);
	crypto_qti_disable(hba->crypto_vops->priv);
}


static int ufshcd_crypto_qti_keyslot_program(struct keyslot_manager *ksm,
					     const struct blk_crypto_key *key,
					     unsigned int slot)
{
	struct ufs_hba *hba = keyslot_manager_private(ksm);
	int err = 0;
	u8 data_unit_mask;
	int crypto_alg_id;

	crypto_alg_id = ufshcd_crypto_cap_find(hba, key->crypto_mode,
					       key->data_unit_size);

	if (!ufshcd_is_crypto_enabled(hba) ||
	    !ufshcd_keyslot_valid(hba, slot) ||
	    !ice_cap_idx_valid(hba, crypto_alg_id))
		return -EINVAL;

	data_unit_mask = get_data_unit_size_mask(key->data_unit_size);

	if (!(data_unit_mask &
	      hba->crypto_cap_array[crypto_alg_id].sdus_mask))
		return -EINVAL;

	pm_runtime_get_sync(hba->dev);
	err = ufshcd_hold(hba, false);
	if (err) {
		pr_err("%s: failed to enable clocks, err %d\n", __func__, err);
		return err;
	}

	err = crypto_qti_keyslot_program(hba->crypto_vops->priv, key, slot,
					data_unit_mask, crypto_alg_id);
	if (err) {
		pr_err("%s: failed with error %d\n", __func__, err);
		ufshcd_release(hba);
		pm_runtime_put_sync(hba->dev);
		return err;
	}

	ufshcd_release(hba);
	pm_runtime_put_sync(hba->dev);

	return 0;
}

static int ufshcd_crypto_qti_keyslot_evict(struct keyslot_manager *ksm,
					   const struct blk_crypto_key *key,
					   unsigned int slot)
{
	int err = 0;
	struct ufs_hba *hba = keyslot_manager_private(ksm);

	if (!ufshcd_is_crypto_enabled(hba) ||
	    !ufshcd_keyslot_valid(hba, slot))
		return -EINVAL;

	pm_runtime_get_sync(hba->dev);
	err = ufshcd_hold(hba, false);
	if (err) {
		pr_err("%s: failed to enable clocks, err %d\n", __func__, err);
		return err;
	}

	err = crypto_qti_keyslot_evict(hba->crypto_vops->priv, slot);
	if (err) {
		pr_err("%s: failed with error %d\n",
			__func__, err);
		ufshcd_release(hba);
		pm_runtime_put_sync(hba->dev);
		return err;
	}

	ufshcd_release(hba);
	pm_runtime_put_sync(hba->dev);

	return err;
}

static int ufshcd_crypto_qti_derive_raw_secret(struct keyslot_manager *ksm,
					       const u8 *wrapped_key,
					       unsigned int wrapped_key_size,
					       u8 *secret,
					       unsigned int secret_size)
{
	return crypto_qti_derive_raw_secret(wrapped_key, wrapped_key_size,
			secret, secret_size);
}

static const struct keyslot_mgmt_ll_ops ufshcd_crypto_qti_ksm_ops = {
	.keyslot_program	= ufshcd_crypto_qti_keyslot_program,
	.keyslot_evict		= ufshcd_crypto_qti_keyslot_evict,
	.derive_raw_secret	= ufshcd_crypto_qti_derive_raw_secret,
};

static enum blk_crypto_mode_num ufshcd_blk_crypto_qti_mode_num_for_alg_dusize(
					enum ufs_crypto_alg ufs_crypto_alg,
					enum ufs_crypto_key_size key_size)
{
	/*
	 * This is currently the only mode that UFS and blk-crypto both support.
	 */
	if (ufs_crypto_alg == UFS_CRYPTO_ALG_AES_XTS &&
		key_size == UFS_CRYPTO_KEY_SIZE_256)
		return BLK_ENCRYPTION_MODE_AES_256_XTS;

	return BLK_ENCRYPTION_MODE_INVALID;
}

static int ufshcd_hba_init_crypto_qti_spec(struct ufs_hba *hba,
				    const struct keyslot_mgmt_ll_ops *ksm_ops)
{
	int cap_idx = 0;
	int err = 0;
	unsigned int crypto_modes_supported[BLK_ENCRYPTION_MODE_MAX];
	enum blk_crypto_mode_num blk_mode_num;

	/* Default to disabling crypto */
	hba->caps &= ~UFSHCD_CAP_CRYPTO;

	if (!(hba->capabilities & MASK_CRYPTO_SUPPORT)) {
		err = -ENODEV;
		goto out;
	}

	/*
	 * Crypto Capabilities should never be 0, because the
	 * config_array_ptr > 04h. So we use a 0 value to indicate that
	 * crypto init failed, and can't be enabled.
	 */
	hba->crypto_capabilities.reg_val =
			  cpu_to_le32(ufshcd_readl(hba, REG_UFS_CCAP));
	hba->crypto_cfg_register =
		 (u32)hba->crypto_capabilities.config_array_ptr * 0x100;
	hba->crypto_cap_array =
		 devm_kcalloc(hba->dev,
				hba->crypto_capabilities.num_crypto_cap,
				sizeof(hba->crypto_cap_array[0]),
				GFP_KERNEL);
	if (!hba->crypto_cap_array) {
		err = -ENOMEM;
		goto out;
	}

	memset(crypto_modes_supported, 0, sizeof(crypto_modes_supported));
	/*
	 * Store all the capabilities now so that we don't need to repeatedly
	 * access the device each time we want to know its capabilities
	 */
	for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap;
	     cap_idx++) {
		hba->crypto_cap_array[cap_idx].reg_val =
				cpu_to_le32(ufshcd_readl(hba,
						REG_UFS_CRYPTOCAP +
						cap_idx * sizeof(__le32)));
		blk_mode_num = ufshcd_blk_crypto_qti_mode_num_for_alg_dusize(
				hba->crypto_cap_array[cap_idx].algorithm_id,
				hba->crypto_cap_array[cap_idx].key_size);
		if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID)
			continue;
		crypto_modes_supported[blk_mode_num] |=
			hba->crypto_cap_array[cap_idx].sdus_mask * 512;
	}

	hba->ksm = keyslot_manager_create(ufshcd_num_keyslots(hba), ksm_ops,
					crypto_modes_supported, hba);

	if (!hba->ksm) {
		err = -ENOMEM;
		goto out;
	}
	pr_debug("%s: keyslot manager created\n", __func__);

	return 0;

out:
	/* Indicate that init failed by setting crypto_capabilities to 0 */
	hba->crypto_capabilities.reg_val = 0;
	return err;
}

int ufshcd_crypto_qti_init_crypto(struct ufs_hba *hba,
				  const struct keyslot_mgmt_ll_ops *ksm_ops)
{
	int err = 0;
	struct platform_device *pdev = to_platform_device(hba->dev);
	void __iomem *mmio_base;
	struct resource *mem_res;

	mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
								"ufs_ice");
	mmio_base = devm_ioremap_resource(hba->dev, mem_res);
	if (IS_ERR(mmio_base)) {
		pr_err("%s: Unable to get ufs_crypto mmio base\n", __func__);
		return PTR_ERR(mmio_base);
	}

	err = ufshcd_hba_init_crypto_qti_spec(hba, &ufshcd_crypto_qti_ksm_ops);
	if (err) {
		pr_err("%s: Error initiating crypto capabilities, err %d\n",
					__func__, err);
		return err;
	}

	err = crypto_qti_init_crypto(hba->dev,
			mmio_base, (void **)&hba->crypto_vops->priv);
	if (err) {
		pr_err("%s: Error initiating crypto, err %d\n",
					__func__, err);
	}
	return err;
}

int ufshcd_crypto_qti_debug(struct ufs_hba *hba)
{
	return crypto_qti_debug(hba->crypto_vops->priv);
}

void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba)
{
	return ufshcd_crypto_set_vops(hba, &ufshcd_crypto_qti_variant_ops);
}

int ufshcd_crypto_qti_resume(struct ufs_hba *hba,
			     enum ufs_pm_op pm_op)
{
	return crypto_qti_resume(hba->crypto_vops->priv);
}

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("UFS Crypto ops QTI implementation");
Loading