From patchwork Wed Nov 3 23:18:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12601951 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03DEAC433F5 for ; Wed, 3 Nov 2021 23:19:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D233B611C5 for ; Wed, 3 Nov 2021 23:19:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229964AbhKCXWS (ORCPT ); Wed, 3 Nov 2021 19:22:18 -0400 Received: from alexa-out-sd-02.qualcomm.com ([199.106.114.39]:29974 "EHLO alexa-out-sd-02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbhKCXWR (ORCPT ); Wed, 3 Nov 2021 19:22:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1635981580; x=1667517580; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=+t2cANEa/1IoTC56pQvmn/ysdJ4N4sZXsTm8V9FS5Xs=; b=XfWVvA5ag6cpR0wkD22+dZ0RtADZPQICwNeaB88IrbQi86Po4quCW2qh Xel+OMAZ0rv7Du76bd1oazEi4LAicpnb+8+UNLFUchuu2MQKcG74Zhej9 08auW+U0quzb32ocSH6BB5nKN/662PWcVkAkhaTa3SMKzTBy3jsWeFIAg E=; Received: from unknown (HELO ironmsg02-sd.qualcomm.com) ([10.53.140.142]) by alexa-out-sd-02.qualcomm.com with ESMTP; 03 Nov 2021 16:19:40 -0700 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg02-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Nov 2021 16:19:39 -0700 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:39 -0700 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:39 -0700 From: Gaurav Kashyap To: , CC: , , , , , Gaurav Kashyap Subject: [PATCH 1/4] ufs: move ICE functionality to a common library Date: Wed, 3 Nov 2021 16:18:37 -0700 Message-ID: <20211103231840.115521-2-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211103231840.115521-1-quic_gaurkash@quicinc.com> References: <20211103231840.115521-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org The Inline Crypto Engine functionality is not limited to ufs and it can be used by other storage controllers like emmc which have the HW capabilities. It would be better to move this functionality to a common location. Moreover, when wrapped key functionality is added, it would reduce the effort required to add it for all storage controllers. Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/ufs-qcom-ice.c | 172 ++++-------------------------- drivers/soc/qcom/Kconfig | 7 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qti-ice-common.c | 135 +++++++++++++++++++++++ drivers/soc/qcom/qti-ice-regs.h | 145 +++++++++++++++++++++++++ include/linux/qti-ice-common.h | 26 +++++ 6 files changed, 334 insertions(+), 152 deletions(-) create mode 100644 drivers/soc/qcom/qti-ice-common.c create mode 100644 drivers/soc/qcom/qti-ice-regs.h create mode 100644 include/linux/qti-ice-common.h diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index bbb0ad7590ec..6608a9015eab 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -8,96 +8,18 @@ #include #include +#include #include "ufshcd-crypto.h" #include "ufs-qcom.h" -#define AES_256_XTS_KEY_SIZE 64 - -/* QCOM ICE registers */ - -#define QCOM_ICE_REG_CONTROL 0x0000 -#define QCOM_ICE_REG_RESET 0x0004 -#define QCOM_ICE_REG_VERSION 0x0008 -#define QCOM_ICE_REG_FUSE_SETTING 0x0010 -#define QCOM_ICE_REG_PARAMETERS_1 0x0014 -#define QCOM_ICE_REG_PARAMETERS_2 0x0018 -#define QCOM_ICE_REG_PARAMETERS_3 0x001C -#define QCOM_ICE_REG_PARAMETERS_4 0x0020 -#define QCOM_ICE_REG_PARAMETERS_5 0x0024 - -/* QCOM ICE v3.X only */ -#define QCOM_ICE_GENERAL_ERR_STTS 0x0040 -#define QCOM_ICE_INVALID_CCFG_ERR_STTS 0x0030 -#define QCOM_ICE_GENERAL_ERR_MASK 0x0044 - -/* QCOM ICE v2.X only */ -#define QCOM_ICE_REG_NON_SEC_IRQ_STTS 0x0040 -#define QCOM_ICE_REG_NON_SEC_IRQ_MASK 0x0044 - -#define QCOM_ICE_REG_NON_SEC_IRQ_CLR 0x0048 -#define QCOM_ICE_REG_STREAM1_ERROR_SYNDROME1 0x0050 -#define QCOM_ICE_REG_STREAM1_ERROR_SYNDROME2 0x0054 -#define QCOM_ICE_REG_STREAM2_ERROR_SYNDROME1 0x0058 -#define QCOM_ICE_REG_STREAM2_ERROR_SYNDROME2 0x005C -#define QCOM_ICE_REG_STREAM1_BIST_ERROR_VEC 0x0060 -#define QCOM_ICE_REG_STREAM2_BIST_ERROR_VEC 0x0064 -#define QCOM_ICE_REG_STREAM1_BIST_FINISH_VEC 0x0068 -#define QCOM_ICE_REG_STREAM2_BIST_FINISH_VEC 0x006C -#define QCOM_ICE_REG_BIST_STATUS 0x0070 -#define QCOM_ICE_REG_BYPASS_STATUS 0x0074 -#define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000 -#define QCOM_ICE_REG_ENDIAN_SWAP 0x1004 -#define QCOM_ICE_REG_TEST_BUS_CONTROL 0x1010 -#define QCOM_ICE_REG_TEST_BUS_REG 0x1014 - -/* BIST ("built-in self-test"?) status flags */ -#define QCOM_ICE_BIST_STATUS_MASK 0xF0000000 - -#define QCOM_ICE_FUSE_SETTING_MASK 0x1 -#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 -#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 - -#define qcom_ice_writel(host, val, reg) \ - writel((val), (host)->ice_mmio + (reg)) -#define qcom_ice_readl(host, reg) \ - readl((host)->ice_mmio + (reg)) - -static bool qcom_ice_supported(struct ufs_qcom_host *host) -{ - struct device *dev = host->hba->dev; - u32 regval = qcom_ice_readl(host, QCOM_ICE_REG_VERSION); - int major = regval >> 24; - int minor = (regval >> 16) & 0xFF; - int step = regval & 0xFFFF; - - /* For now this driver only supports ICE version 3. */ - if (major != 3) { - dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n", - major, minor, step); - return false; - } - - dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", - major, minor, step); - - /* If fuses are blown, ICE might not work in the standard way. */ - regval = qcom_ice_readl(host, QCOM_ICE_REG_FUSE_SETTING); - if (regval & (QCOM_ICE_FUSE_SETTING_MASK | - QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK | - QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) { - dev_warn(dev, "Fuses are blown; ICE is unusable!\n"); - return false; - } - return true; -} - int ufs_qcom_ice_init(struct ufs_qcom_host *host) { struct ufs_hba *hba = host->hba; struct device *dev = hba->dev; struct platform_device *pdev = to_platform_device(dev); struct resource *res; + struct ice_mmio_data mmio; int err; if (!(ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES) & @@ -121,8 +43,9 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host) dev_err(dev, "Failed to map ICE registers; err=%d\n", err); return err; } + mmio.ice_mmio = host->ice_mmio; - if (!qcom_ice_supported(host)) + if (!qti_ice_init(&mmio)) goto disable; return 0; @@ -133,71 +56,31 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host) return 0; } -static void qcom_ice_low_power_mode_enable(struct ufs_qcom_host *host) -{ - u32 regval; - - regval = qcom_ice_readl(host, QCOM_ICE_REG_ADVANCED_CONTROL); - /* - * Enable low power mode sequence - * [0]-0, [1]-0, [2]-0, [3]-E, [4]-0, [5]-0, [6]-0, [7]-0 - */ - regval |= 0x7000; - qcom_ice_writel(host, regval, QCOM_ICE_REG_ADVANCED_CONTROL); -} - -static void qcom_ice_optimization_enable(struct ufs_qcom_host *host) +static void get_ice_mmio_data(struct ice_mmio_data *data, + const struct ufs_qcom_host *host) { - u32 regval; - - /* ICE Optimizations Enable Sequence */ - regval = qcom_ice_readl(host, QCOM_ICE_REG_ADVANCED_CONTROL); - regval |= 0xD807100; - /* ICE HPG requires delay before writing */ - udelay(5); - qcom_ice_writel(host, regval, QCOM_ICE_REG_ADVANCED_CONTROL); - udelay(5); + data->ice_mmio = host->ice_mmio; } int ufs_qcom_ice_enable(struct ufs_qcom_host *host) { + struct ice_mmio_data mmio; + if (!(host->hba->caps & UFSHCD_CAP_CRYPTO)) return 0; - qcom_ice_low_power_mode_enable(host); - qcom_ice_optimization_enable(host); - return ufs_qcom_ice_resume(host); -} - -/* Poll until all BIST bits are reset */ -static int qcom_ice_wait_bist_status(struct ufs_qcom_host *host) -{ - int count; - u32 reg; - - for (count = 0; count < 100; count++) { - reg = qcom_ice_readl(host, QCOM_ICE_REG_BIST_STATUS); - if (!(reg & QCOM_ICE_BIST_STATUS_MASK)) - break; - udelay(50); - } - if (reg) - return -ETIMEDOUT; - return 0; + get_ice_mmio_data(&mmio, host); + return qti_ice_enable(&mmio); } int ufs_qcom_ice_resume(struct ufs_qcom_host *host) { - int err; + struct ice_mmio_data mmio; if (!(host->hba->caps & UFSHCD_CAP_CRYPTO)) return 0; - err = qcom_ice_wait_bist_status(host); - if (err) { - dev_err(host->hba->dev, "BIST status error (%d)\n", err); - return err; - } - return 0; + get_ice_mmio_data(&mmio, host); + return qti_ice_resume(&mmio); } /* @@ -208,16 +91,13 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba, const union ufs_crypto_cfg_entry *cfg, int slot) { union ufs_crypto_cap_entry cap; - union { - u8 bytes[AES_256_XTS_KEY_SIZE]; - u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)]; - } key; - int i; - int err; + struct ice_mmio_data mmio; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE)) - return qcom_scm_ice_invalidate_key(slot); + return qti_ice_keyslot_evict(slot); + get_ice_mmio_data(&mmio, host); /* Only AES-256-XTS has been tested so far. */ cap = hba->crypto_cap_array[cfg->crypto_cap_idx]; if (cap.algorithm_id != UFS_CRYPTO_ALG_AES_XTS || @@ -228,18 +108,6 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba, return -EINVAL; } - memcpy(key.bytes, cfg->crypto_key, AES_256_XTS_KEY_SIZE); - - /* - * The SCM call byte-swaps the 32-bit words of the key. So we have to - * do the same, in order for the final key be correct. - */ - for (i = 0; i < ARRAY_SIZE(key.words); i++) - __cpu_to_be32s(&key.words[i]); - - err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, - QCOM_SCM_ICE_CIPHER_AES_256_XTS, - cfg->data_unit_size); - memzero_explicit(&key, sizeof(key)); - return err; + return qti_ice_keyslot_program(&mmio, cfg->crypto_key, AES_256_XTS_KEY_SIZE, + slot, cfg->data_unit_size, cfg->crypto_cap_idx); } diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 79b568f82a1c..39f223ed8cdd 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -209,4 +209,11 @@ config QCOM_APR application processor and QDSP6. APR is used by audio driver to configure QDSP6 ASM, ADM and AFE modules. + +config QTI_ICE_COMMON + tristate "QTI common ICE functionality" + depends on SCSI_UFS_CRYPTO && SCSI_UFS_QCOM + help + Enable the common ICE library that can be used + by UFS and EMMC drivers for ICE functionality. endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index ad675a6593d0..57840b19b7ee 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o +obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c new file mode 100644 index 000000000000..b344a4cab5d4 --- /dev/null +++ b/drivers/soc/qcom/qti-ice-common.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Common ICE library for storage encryption. + * + * Copyright (c) 2021, Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "qti-ice-regs.h" + +#define QTI_ICE_MAX_BIST_CHECK_COUNT 100 + +static bool qti_ice_supported(const struct ice_mmio_data *mmio) +{ + u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION); + int major = regval >> 24; + int minor = (regval >> 16) & 0xFF; + int step = regval & 0xFFFF; + + /* For now this driver only supports ICE version 3 and higher. */ + if (major < 3) { + pr_warn("Unsupported ICE version: v%d.%d.%d\n", + major, minor, step); + return false; + } + + pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", + major, minor, step); + + /* If fuses are blown, ICE might not work in the standard way. */ + regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_FUSE_SETTING); + if (regval & (QTI_ICE_FUSE_SETTING_MASK | + QTI_ICE_FORCE_HW_KEY0_SETTING_MASK | + QTI_ICE_FORCE_HW_KEY1_SETTING_MASK)) { + pr_warn("Fuses are blown; ICE is unusable!\n"); + return false; + } + return true; +} + +int qti_ice_init(const struct ice_mmio_data *mmio) +{ + return qti_ice_supported(mmio); +} +EXPORT_SYMBOL(qti_ice_init); + +static void qti_ice_low_power_and_optimization_enable( + const struct ice_mmio_data *mmio) +{ + u32 regval = qti_ice_readl(mmio, QTI_ICE_REGS_ADVANCED_CONTROL); + + /* Enable low power mode sequence + * [0]-0,[1]-0,[2]-0,[3]-7,[4]-0,[5]-0,[6]-0,[7]-0, + * Enable CONFIG_CLK_GATING, STREAM2_CLK_GATING and STREAM1_CLK_GATING + */ + regval |= 0x7000; + /* Optimization enable sequence*/ + regval |= 0xD807100; + qti_ice_writel(mmio, regval, QTI_ICE_REGS_ADVANCED_CONTROL); + /* Memory barrier - to ensure write completion before next transaction */ + wmb(); +} + +static int qti_ice_wait_bist_status(const struct ice_mmio_data *mmio) +{ + int count; + u32 regval; + + for (count = 0; count < QTI_ICE_MAX_BIST_CHECK_COUNT; count++) { + regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_BIST_STATUS); + if (!(regval & QTI_ICE_BIST_STATUS_MASK)) + break; + udelay(50); + } + + if (regval) { + pr_err("%s: wait bist status failed, reg %d\n", __func__, regval); + return -ETIMEDOUT; + } + + return 0; +} + +int qti_ice_enable(const struct ice_mmio_data *mmio) +{ + qti_ice_low_power_and_optimization_enable(mmio); + return qti_ice_wait_bist_status(mmio); +} +EXPORT_SYMBOL(qti_ice_enable); + +int qti_ice_resume(const struct ice_mmio_data *mmio) +{ + return qti_ice_wait_bist_status(mmio); +} +EXPORT_SYMBOL(qti_ice_resume); + +int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, + const u8* crypto_key, unsigned int crypto_key_size, + unsigned int slot, u8 data_unit_mask, int capid) +{ + int err = 0; + int i = 0; + union { + u8 bytes[AES_256_XTS_KEY_SIZE]; + u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)]; + } key; + + memcpy(key.bytes, crypto_key, crypto_key_size); + /* + * The SCM call byte-swaps the 32-bit words of the key. So we have to + * do the same, in order for the final key be correct. + */ + for (i = 0; i < ARRAY_SIZE(key.words); i++) + __cpu_to_be32s(&key.words[i]); + + err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, + capid, data_unit_mask); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", __func__, err, slot); + + memzero_explicit(&key, sizeof(key)); + return err; +} +EXPORT_SYMBOL(qti_ice_keyslot_program); + +int qti_ice_keyslot_evict(unsigned int slot) +{ + return qcom_scm_ice_invalidate_key(slot); +} +EXPORT_SYMBOL(qti_ice_keyslot_evict); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/qti-ice-regs.h b/drivers/soc/qcom/qti-ice-regs.h new file mode 100644 index 000000000000..47c625c9d536 --- /dev/null +++ b/drivers/soc/qcom/qti-ice-regs.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ +#define _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ + +#include + +/* QTI ICE Registers from SWI */ +#define QTI_ICE_REGS_CONTROL 0x0000 +#define QTI_ICE_REGS_RESET 0x0004 +#define QTI_ICE_REGS_VERSION 0x0008 +#define QTI_ICE_REGS_FUSE_SETTING 0x0010 +#define QTI_ICE_REGS_PARAMETERS_1 0x0014 +#define QTI_ICE_REGS_PARAMETERS_2 0x0018 +#define QTI_ICE_REGS_PARAMETERS_3 0x001C +#define QTI_ICE_REGS_PARAMETERS_4 0x0020 +#define QTI_ICE_REGS_PARAMETERS_5 0x0024 + +/* Register bits for ICE version */ +#define QTI_ICE_CORE_STEP_REV_MASK 0xFFFF +#define QTI_ICE_CORE_STEP_REV 0 /* bit 15-0 */ +#define QTI_ICE_CORE_MAJOR_REV_MASK 0xFF000000 +#define QTI_ICE_CORE_MAJOR_REV 24 /* bit 31-24 */ +#define QTI_ICE_CORE_MINOR_REV_MASK 0xFF0000 +#define QTI_ICE_CORE_MINOR_REV 16 /* bit 23-16 */ + +#define QTI_ICE_BIST_STATUS_MASK (0xF0000000) /* bits 28-31 */ + +#define QTI_ICE_FUSE_SETTING_MASK 0x1 +#define QTI_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 +#define QTI_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 + +/* QTI ICE v3.X only */ +#define QTI_ICE_INVALID_CCFG_ERR_STTS 0x0030 +#define QTI_ICE_GENERAL_ERR_STTS 0x0040 +#define QTI_ICE_GENERAL_ERR_MASK 0x0044 +#define QTI_ICE_REGS_NON_SEC_IRQ_CLR 0x0048 +#define QTI_ICE_REGS_STREAM1_ERROR_SYNDROME1 0x0050 +#define QTI_ICE_REGS_STREAM1_ERROR_SYNDROME2 0x0054 +#define QTI_ICE_REGS_STREAM2_ERROR_SYNDROME1 0x0058 +#define QTI_ICE_REGS_STREAM2_ERROR_SYNDROME2 0x005C +#define QTI_ICE_REGS_STREAM1_BIST_ERROR_VEC 0x0060 +#define QTI_ICE_REGS_STREAM2_BIST_ERROR_VEC 0x0064 +#define QTI_ICE_REGS_STREAM1_BIST_FINISH_VEC 0x0068 +#define QTI_ICE_REGS_STREAM2_BIST_FINISH_VEC 0x006C +#define QTI_ICE_REGS_BIST_STATUS 0x0070 +#define QTI_ICE_REGS_BYPASS_STATUS 0x0074 +#define QTI_ICE_REGS_ADVANCED_CONTROL 0x1000 +#define QTI_ICE_REGS_ENDIAN_SWAP 0x1004 +#define QTI_ICE_REGS_TEST_BUS_CONTROL 0x1010 +#define QTI_ICE_REGS_TEST_BUS_REG 0x1014 +#define QTI_ICE_REGS_STREAM1_COUNTERS1 0x1100 +#define QTI_ICE_REGS_STREAM1_COUNTERS2 0x1104 +#define QTI_ICE_REGS_STREAM1_COUNTERS3 0x1108 +#define QTI_ICE_REGS_STREAM1_COUNTERS4 0x110C +#define QTI_ICE_REGS_STREAM1_COUNTERS5_MSB 0x1110 +#define QTI_ICE_REGS_STREAM1_COUNTERS5_LSB 0x1114 +#define QTI_ICE_REGS_STREAM1_COUNTERS6_MSB 0x1118 +#define QTI_ICE_REGS_STREAM1_COUNTERS6_LSB 0x111C +#define QTI_ICE_REGS_STREAM1_COUNTERS7_MSB 0x1120 +#define QTI_ICE_REGS_STREAM1_COUNTERS7_LSB 0x1124 +#define QTI_ICE_REGS_STREAM1_COUNTERS8_MSB 0x1128 +#define QTI_ICE_REGS_STREAM1_COUNTERS8_LSB 0x112C +#define QTI_ICE_REGS_STREAM1_COUNTERS9_MSB 0x1130 +#define QTI_ICE_REGS_STREAM1_COUNTERS9_LSB 0x1134 +#define QTI_ICE_REGS_STREAM2_COUNTERS1 0x1200 +#define QTI_ICE_REGS_STREAM2_COUNTERS2 0x1204 +#define QTI_ICE_REGS_STREAM2_COUNTERS3 0x1208 +#define QTI_ICE_REGS_STREAM2_COUNTERS4 0x120C +#define QTI_ICE_REGS_STREAM2_COUNTERS5_MSB 0x1210 +#define QTI_ICE_REGS_STREAM2_COUNTERS5_LSB 0x1214 +#define QTI_ICE_REGS_STREAM2_COUNTERS6_MSB 0x1218 +#define QTI_ICE_REGS_STREAM2_COUNTERS6_LSB 0x121C +#define QTI_ICE_REGS_STREAM2_COUNTERS7_MSB 0x1220 +#define QTI_ICE_REGS_STREAM2_COUNTERS7_LSB 0x1224 +#define QTI_ICE_REGS_STREAM2_COUNTERS8_MSB 0x1228 +#define QTI_ICE_REGS_STREAM2_COUNTERS8_LSB 0x122C +#define QTI_ICE_REGS_STREAM2_COUNTERS9_MSB 0x1230 +#define QTI_ICE_REGS_STREAM2_COUNTERS9_LSB 0x1234 + +#define QTI_ICE_STREAM1_PREMATURE_LBA_CHANGE (1L << 0) +#define QTI_ICE_STREAM2_PREMATURE_LBA_CHANGE (1L << 1) +#define QTI_ICE_STREAM1_NOT_EXPECTED_LBO (1L << 2) +#define QTI_ICE_STREAM2_NOT_EXPECTED_LBO (1L << 3) +#define QTI_ICE_STREAM1_NOT_EXPECTED_DUN (1L << 4) +#define QTI_ICE_STREAM2_NOT_EXPECTED_DUN (1L << 5) +#define QTI_ICE_STREAM1_NOT_EXPECTED_DUS (1L << 6) +#define QTI_ICE_STREAM2_NOT_EXPECTED_DUS (1L << 7) +#define QTI_ICE_STREAM1_NOT_EXPECTED_DBO (1L << 8) +#define QTI_ICE_STREAM2_NOT_EXPECTED_DBO (1L << 9) +#define QTI_ICE_STREAM1_NOT_EXPECTED_ENC_SEL (1L << 10) +#define QTI_ICE_STREAM2_NOT_EXPECTED_ENC_SEL (1L << 11) +#define QTI_ICE_STREAM1_NOT_EXPECTED_CONF_IDX (1L << 12) +#define QTI_ICE_STREAM2_NOT_EXPECTED_CONF_IDX (1L << 13) +#define QTI_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS (1L << 14) +#define QTI_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS (1L << 15) + +#define QTI_ICE_NON_SEC_IRQ_MASK \ + (QTI_ICE_STREAM1_PREMATURE_LBA_CHANGE | \ + QTI_ICE_STREAM2_PREMATURE_LBA_CHANGE | \ + QTI_ICE_STREAM1_NOT_EXPECTED_LBO | \ + QTI_ICE_STREAM2_NOT_EXPECTED_LBO | \ + QTI_ICE_STREAM1_NOT_EXPECTED_DUN | \ + QTI_ICE_STREAM2_NOT_EXPECTED_DUN | \ + QTI_ICE_STREAM2_NOT_EXPECTED_DUS | \ + QTI_ICE_STREAM1_NOT_EXPECTED_DBO | \ + QTI_ICE_STREAM2_NOT_EXPECTED_DBO | \ + QTI_ICE_STREAM1_NOT_EXPECTED_ENC_SEL | \ + QTI_ICE_STREAM2_NOT_EXPECTED_ENC_SEL | \ + QTI_ICE_STREAM1_NOT_EXPECTED_CONF_IDX |\ + QTI_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS |\ + QTI_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS) + +/* QTI ICE registers from secure side */ +#define QTI_ICE_TEST_BUS_REG_SECURE_INTR (1L << 28) +#define QTI_ICE_TEST_BUS_REG_NON_SECURE_INTR (1L << 2) + +#define QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 0x4040 +#define QTI_ICE_LUT_KEYS_CRYPTOCFG_R_17 0x4044 +#define QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET 0x80 + +#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_STTS 0x6200 +#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_MASK 0x6204 +#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_CLR 0x6208 + +#define QTI_ICE_STREAM1_PARTIALLY_SET_KEY_USED (1L << 0) +#define QTI_ICE_STREAM2_PARTIALLY_SET_KEY_USED (1L << 1) +#define QTI_ICE_QTIC_DBG_OPEN_EVENT (1L << 30) +#define QTI_ICE_KEYS_RAM_RESET_COMPLETED (1L << 31) + +#define QTI_ICE_SEC_IRQ_MASK \ + (QTI_ICE_STREAM1_PARTIALLY_SET_KEY_USED |\ + QTI_ICE_STREAM2_PARTIALLY_SET_KEY_USED |\ + QTI_ICE_QTIC_DBG_OPEN_EVENT | \ + QTI_ICE_KEYS_RAM_RESET_COMPLETED) + +#define qti_ice_writel(mmio, val, reg) \ + writel_relaxed((val), mmio + (reg)) +#define qti_ice_readl(mmio, reg) \ + readl_relaxed(mmio + (reg)) + +#endif /* _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ */ diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h new file mode 100644 index 000000000000..433422b34a7d --- /dev/null +++ b/include/linux/qti-ice-common.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _QTI_ICE_COMMON_H +#define _QTI_ICE_COMMON_H + +#include +#include + +#define AES_256_XTS_KEY_SIZE 64 + +struct ice_mmio_data { + void __iomem *ice_mmio; +}; + +int qti_ice_init(const struct ice_mmio_data *mmio); +int qti_ice_enable(const struct ice_mmio_data *mmio); +int qti_ice_resume(const struct ice_mmio_data *mmio); +int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, + const u8* key, unsigned int key_size, + unsigned int slot, u8 data_unit_mask, int capid); +int qti_ice_keyslot_evict(unsigned int slot); + +#endif /* _QTI_ICE_COMMON_H */ From patchwork Wed Nov 3 23:18:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12601953 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2030C433F5 for ; Wed, 3 Nov 2021 23:19:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A78DF611C3 for ; Wed, 3 Nov 2021 23:19:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230168AbhKCXWY (ORCPT ); Wed, 3 Nov 2021 19:22:24 -0400 Received: from alexa-out-sd-02.qualcomm.com ([199.106.114.39]:4895 "EHLO alexa-out-sd-02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229792AbhKCXWY (ORCPT ); Wed, 3 Nov 2021 19:22:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1635981587; x=1667517587; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=4ZYvYoTiiYdoHo7mT3NR1k5ppIMkCL++FAnd9VzklOg=; b=ef+3/wsn4pj/vohI+gEE2WImk05sFlUl5STJuY3uqScSiVdCLJaqDjJ0 XcHqQhjdjSNG5uMvfgjkM+sjZU5GdjH5wrfI6rrZSXxiKru6VtiYG02vh Q97NVMdQAosvB4Lp3uzV0eaThJwc2uIvBplg8BCpJsWqw0dlq/lymJiYo k=; Received: from unknown (HELO ironmsg-SD-alpha.qualcomm.com) ([10.53.140.30]) by alexa-out-sd-02.qualcomm.com with ESMTP; 03 Nov 2021 16:19:47 -0700 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg-SD-alpha.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Nov 2021 16:19:46 -0700 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:46 -0700 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:46 -0700 From: Gaurav Kashyap To: , CC: , , , , , Gaurav Kashyap Subject: [PATCH 2/4] qcom_scm: scm call for deriving a software secret Date: Wed, 3 Nov 2021 16:18:38 -0700 Message-ID: <20211103231840.115521-3-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211103231840.115521-1-quic_gaurkash@quicinc.com> References: <20211103231840.115521-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Storage encryption requires fscrypt deriving a sw secret from the keys inserted into the linux keyring. For non-wrapped keys, this can be directly done as keys are in the clear. However, when keys are hardware wrapped, it can be only unwrapped by Qualcomm Trustzone. Hence, it also makes sense that the software secret is also derived there and returned to the linux kernel for wrapped keys. Fscrypt invokes this functionality using the crypto profile APIs provided by the block layer. Signed-off-by: Gaurav Kashyap --- drivers/firmware/qcom_scm.c | 61 +++++++++++++++++++++++++++++++++++++ drivers/firmware/qcom_scm.h | 1 + include/linux/qcom_scm.h | 5 +++ 3 files changed, 67 insertions(+) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 2ee97bab7440..cf62e8056c17 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1062,6 +1062,67 @@ int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, } EXPORT_SYMBOL(qcom_scm_ice_set_key); +/** + * qcom_scm_derive_sw_secret() - Derive SW secret from wrapped encryption key + * @wrapped_key: the wrapped key used for inline encryption + * @wrapped_key_size: size of the wrapped key + * @sw_secret: the secret to be derived + * @secret_size: size of the secret derived + * + * Derive a SW secret to be used for inline encryption using Qualcomm ICE. + * + * Generally, for non-wrapped keys, fscrypt can derive a sw secret from the + * key in the clear in the linux keyring. + * + * However, for wrapped keys, the key needs to be unwrapped, which can be done + * only by the secure EE. So, it makes sense for the secure EE to derive the + * sw secret and return to the kernel when wrapped keys are used. + * + * Return: 0 on success; -errno on failure. + */ +int qcom_scm_derive_sw_secret(const u8* wrapped_key, u32 wrapped_key_size, + u8 *sw_secret, u32 secret_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_ES, + .cmd = QCOM_SCM_ES_DERIVE_RAW_SECRET, + .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, + QCOM_SCM_VAL, QCOM_SCM_RW, + QCOM_SCM_VAL), + .args[1] = wrapped_key_size, + .args[3] = secret_size, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + void *keybuf, *secretbuf; + dma_addr_t key_phys, secret_phys; + int ret; + + keybuf = dma_alloc_coherent(__scm->dev, wrapped_key_size, &key_phys, + GFP_KERNEL); + if (!keybuf) + return -ENOMEM; + secretbuf = dma_alloc_coherent(__scm->dev, secret_size, &secret_phys, + GFP_KERNEL); + if (!secretbuf) + return -ENOMEM; + + memcpy(keybuf, wrapped_key, wrapped_key_size); + desc.args[0] = key_phys; + desc.args[2] = secret_phys; + + ret = qcom_scm_call(__scm->dev, &desc, NULL); + memcpy(sw_secret, secretbuf, secret_size); + + memzero_explicit(keybuf, wrapped_key_size); + dma_free_coherent(__scm->dev, wrapped_key_size, keybuf, key_phys); + memzero_explicit(secretbuf, secret_size); + dma_free_coherent(__scm->dev, secret_size, secretbuf, secret_phys); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_derive_sw_secret); + /** * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. * diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index d92156ceb3ac..de5d4f8fd20d 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -110,6 +110,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */ #define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03 #define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04 +#define QCOM_SCM_ES_DERIVE_RAW_SECRET 0x07 #define QCOM_SCM_SVC_HDCP 0x11 #define QCOM_SCM_HDCP_INVOKE 0x01 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index c0475d1c9885..e1f645d714f9 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -103,6 +103,8 @@ extern int qcom_scm_ice_invalidate_key(u32 index); extern int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, enum qcom_scm_ice_cipher cipher, u32 data_unit_size); +extern int qcom_scm_derive_sw_secret(const u8* wrapped_key, + u32 wrapped_key_size, u8 *sw_secret, u32 secret_size); extern bool qcom_scm_hdcp_available(void); extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, @@ -169,6 +171,9 @@ static inline int qcom_scm_ice_invalidate_key(u32 index) { return -ENODEV; } static inline int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, enum qcom_scm_ice_cipher cipher, u32 data_unit_size) { return -ENODEV; } +static inline int qcom_scm_derive_sw_secret(const u8* wrapped_key, + u32 wrapped_key_size, u8 *sw_secret, + u32 secret_size) { return -ENODEV; } static inline bool qcom_scm_hdcp_available(void) { return false; } static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, From patchwork Wed Nov 3 23:18:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12601955 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80C96C4167B for ; Wed, 3 Nov 2021 23:19:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6A3BC611C3 for ; Wed, 3 Nov 2021 23:19:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230301AbhKCXW1 (ORCPT ); Wed, 3 Nov 2021 19:22:27 -0400 Received: from alexa-out.qualcomm.com ([129.46.98.28]:4756 "EHLO alexa-out.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229792AbhKCXW0 (ORCPT ); Wed, 3 Nov 2021 19:22:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1635981590; x=1667517590; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=CWgzDFgrRvUk/uk2a/JrYphlhenWdze50BxsUZFep0s=; b=ICySOIdO8c+T6vvvP177JHDbE+Z0Z3pWF5l4fZb8pXhq+OdlIbqoRrGL 5k57pQh2XplKm+cwLSFCj2k/wk6OklwTi0YjwKFA9xnU0anfvrUxUQQ9M bVkoQSM7jDNWSXbqBqi5UojEtcp8MfIQgFKRJuHJTmCGwsWWsoJ3C+E8D o=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 03 Nov 2021 16:19:49 -0700 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Nov 2021 16:19:49 -0700 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:48 -0700 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:48 -0700 From: Gaurav Kashyap To: , CC: , , , , , Gaurav Kashyap Subject: [PATCH 3/4] soc: qcom: add HWKM library for storage encryption Date: Wed, 3 Nov 2021 16:18:39 -0700 Message-ID: <20211103231840.115521-4-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211103231840.115521-1-quic_gaurkash@quicinc.com> References: <20211103231840.115521-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Wrapped keys should utilize hardware to protect the keys used for storage encryption. Qualcomm's Inline Crypto Engine supports a hardware block called Hardware Key Manager (HWKM) for key management. Although most of the interactions to this hardware block happens via a secure execution environment, some initializations for the slave present in ICE can be done from the kernel. This can also be a placeholder for when the hardware provides more capabilites to be acessed from the linux kernel in the future. Signed-off-by: Gaurav Kashyap --- drivers/soc/qcom/Kconfig | 7 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qti-ice-hwkm.c | 77 ++++++++++++++++++++++ drivers/soc/qcom/qti-ice-regs.h | 112 ++++++++++++++++++++++++++++++++ include/linux/qti-ice-common.h | 6 ++ 5 files changed, 203 insertions(+) create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 39f223ed8cdd..d441d5b81c53 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -216,4 +216,11 @@ config QTI_ICE_COMMON help Enable the common ICE library that can be used by UFS and EMMC drivers for ICE functionality. + +config QTI_HW_WRAPPED_KEYS + tristate "QTI HW Wrapped Keys" + depends on QTI_ICE_COMMON + help + Enable wrapped key functionality for storage + encryption. endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 57840b19b7ee..56d1f4b8d436 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o +obj-$(CONFIG_QTI_HW_WRAPPED_KEYS) += qti-ice-hwkm.o diff --git a/drivers/soc/qcom/qti-ice-hwkm.c b/drivers/soc/qcom/qti-ice-hwkm.c new file mode 100644 index 000000000000..d65873745999 --- /dev/null +++ b/drivers/soc/qcom/qti-ice-hwkm.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HWKM ICE library for storage encryption. + * + * Copyright (c) 2021, Linux Foundation. All rights reserved. + */ + +#include +#include "qti-ice-regs.h" + +static int qti_ice_hwkm_bist_status(const struct ice_mmio_data *mmio, int version) +{ + if (!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? BIST_DONE_V1 : BIST_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? CRYPTO_LIB_BIST_DONE_V1 : + CRYPTO_LIB_BIST_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? BOOT_CMD_LIST1_DONE_V1 : + BOOT_CMD_LIST1_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? BOOT_CMD_LIST0_DONE_V1 : + BOOT_CMD_LIST0_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? KT_CLEAR_DONE_V1 : + KT_CLEAR_DONE_V2)) + return -EINVAL; + return 0; +} + +static int qti_ice_hwkm_init_sequence(const struct ice_mmio_data *mmio, + int version) +{ + u32 val = 0; + + /* + * Put ICE in standard mode, ICE defaults to legacy mode. + * Legacy mode - ICE HWKM slave not supported. + * Standard mode - ICE HWKM slave supported. + * + * Depending on the version of HWKM, it is controlled by different + * registers in ICE. + */ + if (version >= 2) { + val = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_CONTROL); + val = val & 0xFFFFFFFE; + qti_ice_writel(mmio->ice_mmio, val, QTI_ICE_REGS_CONTROL); + } else { + qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0x7, + QTI_HWKM_ICE_RG_TZ_KM_CTL); + } + + /* Check BIST status */ + if (qti_ice_hwkm_bist_status(mmio, version)) + return -EINVAL; + + /* Disable CRC check */ + qti_ice_hwkm_clearb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_CTL, + CRC_CHECK_EN); + + /* Set RSP_FIFO_FULL bit */ + qti_ice_hwkm_setb(mmio->ice_hwkm_mmio, + QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS, RSP_FIFO_FULL); + + return 0; +} + +int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version) +{ + if (!mmio->ice_hwkm_mmio) + return -EINVAL; + + return qti_ice_hwkm_init_sequence(mmio, version); +} +EXPORT_SYMBOL(qti_ice_hwkm_init); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/qti-ice-regs.h b/drivers/soc/qcom/qti-ice-regs.h index 47c625c9d536..4c8d9fd62e42 100644 --- a/drivers/soc/qcom/qti-ice-regs.h +++ b/drivers/soc/qcom/qti-ice-regs.h @@ -137,9 +137,121 @@ QTI_ICE_QTIC_DBG_OPEN_EVENT | \ QTI_ICE_KEYS_RAM_RESET_COMPLETED) +/* Read/write macros for ICE address space */ #define qti_ice_writel(mmio, val, reg) \ writel_relaxed((val), mmio + (reg)) #define qti_ice_readl(mmio, reg) \ readl_relaxed(mmio + (reg)) +/* Registers for ICE HWKM Slave */ + +#define HWKM_VERSION_STEP_REV_MASK 0xFFFF +#define HWKM_VERSION_STEP_REV 0 /* bit 15-0 */ +#define HWKM_VERSION_MAJOR_REV_MASK 0xFF000000 +#define HWKM_VERSION_MAJOR_REV 24 /* bit 31-24 */ +#define HWKM_VERSION_MINOR_REV_MASK 0xFF0000 +#define HWKM_VERSION_MINOR_REV 16 /* bit 23-16 */ + +/* QTI HWKM ICE slave config and status registers */ + +#define QTI_HWKM_ICE_RG_IPCAT_VERSION 0x0000 +#define QTI_HWKM_ICE_RG_KEY_POLICY_VERSION 0x0004 +#define QTI_HWKM_ICE_RG_SHARED_STATUS 0x0008 +#define QTI_HWKM_ICE_RG_KEYTABLE_SIZE 0x000C + +#define QTI_HWKM_ICE_RG_TZ_KM_CTL 0x1000 +#define QTI_HWKM_ICE_RG_TZ_KM_STATUS 0x1004 +#define QTI_HWKM_ICE_RG_TZ_KM_STATUS_IRQ_MASK 0x1008 +#define QTI_HWKM_ICE_RG_TZ_KM_BOOT_STAGE_OTP 0x100C +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_CTL 0x1010 +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_WRITE 0x1014 +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_READ 0x1018 +#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL 0x101C +#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_STATUS 0x1020 +#define QTI_HWKM_ICE_RG_TZ_KM_COMMON_IRQ_ROUTING 0x1024 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_CTL */ +#define CRC_CHECK_EN 0 +#define KEYTABLE_HW_WR_ACCESS_EN 1 +#define KEYTABLE_HW_RD_ACCESS_EN 2 +#define BOOT_INIT0_DISABLE 3 +#define BOOT_INIT1_DISABLE 4 +#define ICE_LEGACY_MODE_EN_OTP 5 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_STATUS for v2 and above*/ +#define KT_CLEAR_DONE_V2 0 +#define BOOT_CMD_LIST0_DONE_V2 1 +#define BOOT_CMD_LIST1_DONE_V2 2 +#define LAST_ACTIVITY_BANK_V2 3 +#define CRYPTO_LIB_BIST_ERROR_V2 6 +#define CRYPTO_LIB_BIST_DONE_V2 7 +#define BIST_ERROR_V2 8 +#define BIST_DONE_V2 9 +#define LAST_ACTIVITY_BANK_MASK_V2 0x38 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_STATUS for v1*/ +#define KT_CLEAR_DONE_V1 0 +#define BOOT_CMD_LIST0_DONE_V1 1 +#define BOOT_CMD_LIST1_DONE_V1 2 +#define KEYTABLE_KEY_POLICY_V1 3 +#define KEYTABLE_INTEGRITY_ERROR_V1 4 +#define KEYTABLE_KEY_SLOT_ERROR_V1 5 +#define KEYTABLE_KEY_SLOT_NOT_EVEN_ERROR_V1 6 +#define KEYTABLE_KEY_SLOT_OUT_OF_RANGE_V1 7 +#define KEYTABLE_KEY_SIZE_ERROR_V1 8 +#define KEYTABLE_OPERATION_ERROR_V1 9 +#define LAST_ACTIVITY_BANK_V1 10 +#define CRYPTO_LIB_BIST_ERROR_V1 13 +#define CRYPTO_LIB_BIST_DONE_V1 14 +#define BIST_ERROR_V1 15 +#define BIST_DONE_V1 16 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_TPKEY_RECEIVE_CTL */ +#define TPKEY_EN 8 + +/* QTI HWKM ICE slave register bank 0 */ +#define QTI_HWKM_ICE_RG_BANK0_BANKN_CTL 0x2000 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS 0x2004 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS 0x2008 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_MASK 0x200C +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR 0x2010 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR_IRQ_MASK 0x2014 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESYNR 0x2018 + +/* QTI_HWKM_ICE_RG_BANKN_IRQ_STATUS */ +#define ARB_GRAN_WINNER 0 +#define CMD_DONE_BIT 1 +#define RSP_FIFO_NOT_EMPTY 2 +#define RSP_FIFO_FULL 3 +#define RSP_FIFO_UNDERFLOW 4 +#define CMD_FIFO_UNDERFLOW 5 + +/* Read/write macros for ICE HWKM address space */ + +#define qti_ice_hwkm_readl(hwkm_mmio, reg) \ + (readl_relaxed(hwkm_mmio + (reg))) +#define qti_ice_hwkm_writel(hwkm_mmio, val, reg) \ + (writel_relaxed((val), hwkm_mmio + (reg))) +#define qti_ice_hwkm_setb(hwkm_mmio, reg, nr) { \ + u32 val = qti_ice_hwkm_readl(hwkm_mmio, reg); \ + val |= (0x1 << nr); \ + qti_ice_hwkm_writel(hwkm_mmio, val, reg); \ +} +#define qti_ice_hwkm_clearb(hwkm_mmio, reg, nr) { \ + u32 val = qti_ice_hwkm_readl(hwkm_mmio, reg); \ + val &= ~(0x1 << nr); \ + qti_ice_hwkm_writel(hwkm_mmio, val, reg); \ +} + +static inline bool qti_ice_hwkm_testb(void __iomem *ice_hwkm_mmio, + u32 reg, u8 nr) +{ + u32 val = qti_ice_hwkm_readl(ice_hwkm_mmio, reg); + + val = (val >> nr) & 0x1; + if (val == 0) + return false; + return true; +} + #endif /* _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ */ diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h index 433422b34a7d..b0a50a1c6876 100644 --- a/include/linux/qti-ice-common.h +++ b/include/linux/qti-ice-common.h @@ -23,4 +23,10 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, unsigned int slot, u8 data_unit_mask, int capid); int qti_ice_keyslot_evict(unsigned int slot); +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS) +int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version); +#else +static inline int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, + int version) { return -ENODEV; } +#endif /* CONFIG_QTI_HW_WRAPPED_KEYS */ #endif /* _QTI_ICE_COMMON_H */ From patchwork Wed Nov 3 23:18:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12601957 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 70C5CC43219 for ; Wed, 3 Nov 2021 23:19:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 55BB5611C4 for ; Wed, 3 Nov 2021 23:19:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230302AbhKCXWd (ORCPT ); Wed, 3 Nov 2021 19:22:33 -0400 Received: from alexa-out-sd-01.qualcomm.com ([199.106.114.38]:34649 "EHLO alexa-out-sd-01.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230310AbhKCXW3 (ORCPT ); Wed, 3 Nov 2021 19:22:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1635981592; x=1667517592; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=uWdfw0XmJ834AUovZZ/JbeOAxouPkUBpMCRDh1E8t+Y=; b=WnEl7l0EergUk4o1wlMnXpHrbppkvnnsYIEcEHKka497uuLgpZKyeFyB 87Mbvl5xfCAoZdEGy+/0NN0Gx/ltBg1tpw+wFu2ek8eEk2WLRbKJglGOs LPF/fnJcMKfxtQWoPHY/Dd970dEnx+KRPTJD1II5RPofYuWR+f6lOWpgk Q=; Received: from unknown (HELO ironmsg03-sd.qualcomm.com) ([10.53.140.143]) by alexa-out-sd-01.qualcomm.com with ESMTP; 03 Nov 2021 16:19:52 -0700 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg03-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Nov 2021 16:19:51 -0700 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:50 -0700 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Wed, 3 Nov 2021 16:19:49 -0700 From: Gaurav Kashyap To: , CC: , , , , , Gaurav Kashyap Subject: [PATCH 4/4] soc: qcom: add wrapped key support for ICE Date: Wed, 3 Nov 2021 16:18:40 -0700 Message-ID: <20211103231840.115521-5-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211103231840.115521-1-quic_gaurkash@quicinc.com> References: <20211103231840.115521-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Add support for wrapped keys in ufs and common ICE library. Qualcomm's ICE solution uses a hardware block called Hardware Key Manager (HWKM) to handle wrapped keys. This patch adds the following changes to support this. 1. Link to HWKM library for initialization. 2. Most of the key management is done from Trustzone via scm calls. Added calls to this from the ICE library. 3. Added support for this framework in UFS. 4. Added support for deriving SW secret as it cannot be done in linux kernel for wrapped keys. Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/ufs-qcom-ice.c | 34 +++++++++- drivers/scsi/ufs/ufs-qcom.c | 1 + drivers/scsi/ufs/ufs-qcom.h | 5 ++ drivers/scsi/ufs/ufshcd-crypto.c | 47 ++++++++++--- drivers/scsi/ufs/ufshcd.h | 5 ++ drivers/soc/qcom/qti-ice-common.c | 108 ++++++++++++++++++++++++++---- include/linux/qti-ice-common.h | 7 +- 7 files changed, 180 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 6608a9015eab..79d642190997 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -45,6 +45,21 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host) } mmio.ice_mmio = host->ice_mmio; +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS) + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice_hwkm"); + if (!res) { + dev_warn(dev, "ICE HWKM registers not found\n"); + goto disable; + } + + host->ice_hwkm_mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(host->ice_hwkm_mmio)) { + err = PTR_ERR(host->ice_hwkm_mmio); + dev_err(dev, "Failed to map ICE registers; err=%d\n", err); + return err; + } + mmio.ice_hwkm_mmio = host->ice_hwkm_mmio; +#endif if (!qti_ice_init(&mmio)) goto disable; @@ -60,6 +75,9 @@ static void get_ice_mmio_data(struct ice_mmio_data *data, const struct ufs_qcom_host *host) { data->ice_mmio = host->ice_mmio; +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS) + data->ice_hwkm_mmio = host->ice_hwkm_mmio; +#endif } int ufs_qcom_ice_enable(struct ufs_qcom_host *host) @@ -88,6 +106,7 @@ int ufs_qcom_ice_resume(struct ufs_qcom_host *host) * vendor-specific SCM calls for this; it doesn't support the standard way. */ int ufs_qcom_ice_program_key(struct ufs_hba *hba, + const struct blk_crypto_key *key, const union ufs_crypto_cfg_entry *cfg, int slot) { union ufs_crypto_cap_entry cap; @@ -108,6 +127,17 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba, return -EINVAL; } - return qti_ice_keyslot_program(&mmio, cfg->crypto_key, AES_256_XTS_KEY_SIZE, - slot, cfg->data_unit_size, cfg->crypto_cap_idx); + return qti_ice_keyslot_program(&mmio, key, slot, + cfg->data_unit_size, cfg->crypto_cap_idx); +} + +/* + * Derive a SW secret from the wrapped key to be used in fscrypt. The key + * is unwrapped in QTI and a SW key is then derived. + */ +int ufs_qcom_ice_derive_sw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) +{ + return qti_ice_derive_sw_secret(wrapped_key, wrapped_key_size, sw_secret); } diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 9d9770f1db4f..9f85332fbe64 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1495,6 +1495,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .device_reset = ufs_qcom_device_reset, .config_scaling_param = ufs_qcom_config_scaling_param, .program_key = ufs_qcom_ice_program_key, + .derive_secret = ufs_qcom_ice_derive_sw_secret, }; /** diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 8208e3a3ef59..420fdc1dfeaa 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -207,6 +207,7 @@ struct ufs_qcom_host { struct ufs_hw_version hw_ver; #ifdef CONFIG_SCSI_UFS_CRYPTO void __iomem *ice_mmio; + void __iomem *ice_hwkm_mmio; #endif u32 dev_ref_clk_en_mask; @@ -252,7 +253,11 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host); int ufs_qcom_ice_enable(struct ufs_qcom_host *host); int ufs_qcom_ice_resume(struct ufs_qcom_host *host); int ufs_qcom_ice_program_key(struct ufs_hba *hba, + const struct blk_crypto_key *key, const union ufs_crypto_cfg_entry *cfg, int slot); +int ufs_qcom_ice_derive_sw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); #else static inline int ufs_qcom_ice_init(struct ufs_qcom_host *host) { diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c index 0ed82741f981..965a8cc6c183 100644 --- a/drivers/scsi/ufs/ufshcd-crypto.c +++ b/drivers/scsi/ufs/ufshcd-crypto.c @@ -18,6 +18,7 @@ static const struct ufs_crypto_alg_entry { }; static int ufshcd_program_key(struct ufs_hba *hba, + const struct blk_crypto_key *key, const union ufs_crypto_cfg_entry *cfg, int slot) { int i; @@ -27,7 +28,7 @@ static int ufshcd_program_key(struct ufs_hba *hba, ufshcd_hold(hba, false); if (hba->vops && hba->vops->program_key) { - err = hba->vops->program_key(hba, cfg, slot); + err = hba->vops->program_key(hba, key, cfg, slot); goto out; } @@ -80,16 +81,18 @@ static int ufshcd_crypto_keyslot_program(struct blk_crypto_profile *profile, cfg.crypto_cap_idx = cap_idx; cfg.config_enable = UFS_CRYPTO_CONFIGURATION_ENABLE; - if (ccap_array[cap_idx].algorithm_id == UFS_CRYPTO_ALG_AES_XTS) { - /* In XTS mode, the blk_crypto_key's size is already doubled */ - memcpy(cfg.crypto_key, key->raw, key->size/2); - memcpy(cfg.crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2, - key->raw + key->size/2, key->size/2); - } else { - memcpy(cfg.crypto_key, key->raw, key->size); + if (key->crypto_cfg.key_type != BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) { + if (ccap_array[cap_idx].algorithm_id == UFS_CRYPTO_ALG_AES_XTS) { + /* In XTS mode, the blk_crypto_key's size is already doubled */ + memcpy(cfg.crypto_key, key->raw, key->size/2); + memcpy(cfg.crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2, + key->raw + key->size/2, key->size/2); + } else { + memcpy(cfg.crypto_key, key->raw, key->size); + } } - err = ufshcd_program_key(hba, &cfg, slot); + err = ufshcd_program_key(hba, key, &cfg, slot); memzero_explicit(&cfg, sizeof(cfg)); return err; @@ -103,7 +106,7 @@ static int ufshcd_clear_keyslot(struct ufs_hba *hba, int slot) */ union ufs_crypto_cfg_entry cfg = {}; - return ufshcd_program_key(hba, &cfg, slot); + return ufshcd_program_key(hba, NULL, &cfg, slot); } static int ufshcd_crypto_keyslot_evict(struct blk_crypto_profile *profile, @@ -126,9 +129,29 @@ bool ufshcd_crypto_enable(struct ufs_hba *hba) return true; } +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS) +static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) +{ + struct ufs_hba *hba = + container_of(profile, struct ufs_hba, crypto_profile); + + if (hba->vops && hba->vops->derive_secret) + return hba->vops->derive_secret(wrapped_key, + wrapped_key_size, sw_secret); + + return 0; +} +#endif + static const struct blk_crypto_ll_ops ufshcd_crypto_ops = { .keyslot_program = ufshcd_crypto_keyslot_program, .keyslot_evict = ufshcd_crypto_keyslot_evict, +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS) + .derive_sw_secret = ufshcd_crypto_derive_sw_secret, +#endif }; static enum blk_crypto_mode_num @@ -190,7 +213,11 @@ int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba) hba->crypto_profile.ll_ops = ufshcd_crypto_ops; /* UFS only supports 8 bytes for any DUN */ hba->crypto_profile.max_dun_bytes_supported = 8; +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS) + hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_HW_WRAPPED; +#else hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_STANDARD; +#endif hba->crypto_profile.dev = hba->dev; /* diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index df5439b12208..ff712358225d 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -320,6 +320,7 @@ struct ufs_pwr_mode_info { * @device_reset: called to issue a reset pulse on the UFS device * @program_key: program or evict an inline encryption key * @event_notify: called to notify important events + * @derive_secret: derive sw secret from wrapped inline encryption key */ struct ufs_hba_variant_ops { const char *name; @@ -353,9 +354,13 @@ struct ufs_hba_variant_ops { struct devfreq_dev_profile *profile, void *data); int (*program_key)(struct ufs_hba *hba, + const struct blk_crypto_key *crypto_key, const union ufs_crypto_cfg_entry *cfg, int slot); void (*event_notify)(struct ufs_hba *hba, enum ufs_event_type evt, void *data); + int (*derive_secret)(const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); }; /* clock gating state */ diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c index b344a4cab5d4..ffec27087543 100644 --- a/drivers/soc/qcom/qti-ice-common.c +++ b/drivers/soc/qcom/qti-ice-common.c @@ -13,6 +13,23 @@ #define QTI_ICE_MAX_BIST_CHECK_COUNT 100 +/* + * ICE resets during power collapse and HWKM has to be + * reconfigured which can be kept track with this flag. + */ +static bool qti_hwkm_init_done; +static int hwkm_version; + +union crypto_cfg { + __le32 regval; + struct { + u8 dusize; + u8 capidx; + u8 reserved; + u8 cfge; + }; +}; + static bool qti_ice_supported(const struct ice_mmio_data *mmio) { u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION); @@ -27,6 +44,11 @@ static bool qti_ice_supported(const struct ice_mmio_data *mmio) return false; } + if ((major >=4) || ((major == 3) && (minor == 2) && (step >= 1))) + hwkm_version = 2; + else + hwkm_version = 1; + pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", major, minor, step); @@ -97,8 +119,51 @@ int qti_ice_resume(const struct ice_mmio_data *mmio) } EXPORT_SYMBOL(qti_ice_resume); +static int qti_ice_program_wrapped_key(const struct ice_mmio_data *mmio, + const struct blk_crypto_key *crypto_key, + unsigned int slot, u8 data_unit_mask, int capid) +{ + int err = 0; + union crypto_cfg cfg; + + if (!qti_hwkm_init_done) { + err = qti_ice_hwkm_init(mmio, hwkm_version); + if (err) { + pr_err("%s: Error initializing hwkm, err = %d", + __func__, err); + return -EINVAL; + } + qti_hwkm_init_done = true; + } + + memset(&cfg, 0, sizeof(cfg)); + cfg.dusize = data_unit_mask; + cfg.capidx = capid; + cfg.cfge = 0x80; + + /* Make sure CFGE is cleared */ + qti_ice_writel(mmio->ice_mmio, 0x0,(QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 + + QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot)); + wmb(); + + /* Call trustzone to program the wrapped key using hwkm */ + err = qcom_scm_ice_set_key(slot, crypto_key->raw, crypto_key->size, + capid, data_unit_mask); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", + __func__, err, slot); + + /* Make sure CFGE is enabled after programming the key */ + qti_ice_writel(mmio->ice_mmio, cfg.regval, + (QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 + + QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot)); + wmb(); + + return err; +} + int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, - const u8* crypto_key, unsigned int crypto_key_size, + const struct blk_crypto_key *crypto_key, unsigned int slot, u8 data_unit_mask, int capid) { int err = 0; @@ -108,20 +173,26 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)]; } key; - memcpy(key.bytes, crypto_key, crypto_key_size); - /* - * The SCM call byte-swaps the 32-bit words of the key. So we have to - * do the same, in order for the final key be correct. - */ - for (i = 0; i < ARRAY_SIZE(key.words); i++) - __cpu_to_be32s(&key.words[i]); - - err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, - capid, data_unit_mask); - if (err) - pr_err("%s:SCM call Error: 0x%x slot %d\n", __func__, err, slot); + if (crypto_key->crypto_cfg.key_type != BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) { + err = qti_ice_program_wrapped_key(mmio, crypto_key, slot, + data_unit_mask, capid); + } else { + memcpy(key.bytes, crypto_key->raw, crypto_key->size); + /* + * The SCM call byte-swaps the 32-bit words of the key. So we have to + * do the same, in order for the final key be correct. + */ + for (i = 0; i < ARRAY_SIZE(key.words); i++) + __cpu_to_be32s(&key.words[i]); + + err = qcom_scm_ice_set_key(slot, key.bytes, + AES_256_XTS_KEY_SIZE, capid, data_unit_mask); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", + __func__, err, slot); + memzero_explicit(&key, sizeof(key)); + } - memzero_explicit(&key, sizeof(key)); return err; } EXPORT_SYMBOL(qti_ice_keyslot_program); @@ -132,4 +203,13 @@ int qti_ice_keyslot_evict(unsigned int slot) } EXPORT_SYMBOL(qti_ice_keyslot_evict); +int qti_ice_derive_sw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) +{ + return qcom_scm_derive_sw_secret(wrapped_key, wrapped_key_size, + sw_secret, BLK_CRYPTO_SW_SECRET_SIZE); +} +EXPORT_SYMBOL(qti_ice_derive_sw_secret); + MODULE_LICENSE("GPL v2"); diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h index b0a50a1c6876..73365764a595 100644 --- a/include/linux/qti-ice-common.h +++ b/include/linux/qti-ice-common.h @@ -8,23 +8,28 @@ #include #include +#include #define AES_256_XTS_KEY_SIZE 64 struct ice_mmio_data { void __iomem *ice_mmio; + void __iomem *ice_hwkm_mmio; }; int qti_ice_init(const struct ice_mmio_data *mmio); int qti_ice_enable(const struct ice_mmio_data *mmio); int qti_ice_resume(const struct ice_mmio_data *mmio); int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, - const u8* key, unsigned int key_size, + const struct blk_crypto_key *crypto_key, unsigned int slot, u8 data_unit_mask, int capid); int qti_ice_keyslot_evict(unsigned int slot); #if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS) int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version); +int qti_ice_derive_sw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); #else static inline int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version) { return -ENODEV; }