[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251026164708.2771213-1-neeraj.soni@oss.qualcomm.com>
Date: Sun, 26 Oct 2025 22:17:08 +0530
From: Neeraj Soni <neeraj.soni@....qualcomm.com>
To: andersson@...nel.org, konradybcio@...nel.org
Cc: linux-arm-msm@...r.kernel.org, linux-kernel@...r.kernel.org,
neeraj.soni@....qualcomm.com
Subject: [PATCH] soc: qcom: Add HWKM v1 support for wrapped keys
HWKM v1 and v2 differ slightly in wrapped key size and the bit fields for
certain status registers and operating mode (legacy or standard).
Add support to select HWKM version based on the major and minor revisions.
Use this HWKM version to select wrapped key size and to configure the bit
fields in registers for operating modes and hardware status.
Support for SCM calls for wrapped keys is being added in the TrustZone for
few SoCs with HWKM v1. Existing check of qcom_scm_has_wrapped_key_support()
API ensures that HWKM is used only if these SCM calls are supported in
TrustZone for that SoC.
Signed-off-by: Neeraj Soni <neeraj.soni@....qualcomm.com>
---
drivers/soc/qcom/ice.c | 85 ++++++++++++++++++++++++++++++------------
1 file changed, 62 insertions(+), 23 deletions(-)
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index c467b55b4174..5f213e74c668 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -22,7 +22,16 @@
#include <soc/qcom/ice.h>
#define AES_256_XTS_KEY_SIZE 64 /* for raw keys only */
-#define QCOM_ICE_HWKM_WRAPPED_KEY_SIZE 100 /* assuming HWKM v2 */
+
+#define QCOM_ICE_HWKM_V1 1 /* HWKM version 1 */
+#define QCOM_ICE_HWKM_V2 2 /* HWKM version 2 */
+
+/*
+ * Wrapped key size depends upon HWKM version:
+ * HWKM version 1 supports 68 bytes
+ * HWKM version 2 supports 100 bytes
+ */
+#define QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(v) ((v) == QCOM_ICE_HWKM_V1 ? 68 : 100)
/* QCOM ICE registers */
@@ -62,13 +71,15 @@ union crypto_cfg {
#define QCOM_ICE_REG_HWKM_TZ_KM_CTL (HWKM_OFFSET + 0x1000)
#define QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL (BIT(1) | BIT(2))
+/* In HWKM v1 the ICE legacy mode is controlled from HWKM register space */
+#define QCOM_ICE_HWKM_ICE_LEGACY_MODE_ENABLED BIT(5)
#define QCOM_ICE_REG_HWKM_TZ_KM_STATUS (HWKM_OFFSET + 0x1004)
#define QCOM_ICE_HWKM_KT_CLEAR_DONE BIT(0)
#define QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE BIT(1)
#define QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE BIT(2)
-#define QCOM_ICE_HWKM_CRYPTO_BIST_DONE_V2 BIT(7)
-#define QCOM_ICE_HWKM_BIST_DONE_V2 BIT(9)
+#define QCOM_ICE_HWKM_CRYPTO_BIST_DONE(v) (((v) == QCOM_ICE_HWKM_V1) ? BIT(14) : BIT(7))
+#define QCOM_ICE_HWKM_BIST_DONE(v) (((v) == QCOM_ICE_HWKM_V1) ? BIT(16) : BIT(9))
#define QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS (HWKM_OFFSET + 0x2008)
#define QCOM_ICE_HWKM_RSP_FIFO_CLEAR_VAL BIT(3)
@@ -97,6 +108,7 @@ struct qcom_ice {
struct clk *core_clk;
bool use_hwkm;
bool hwkm_init_complete;
+ u8 hwkm_version;
};
static bool qcom_ice_check_supported(struct qcom_ice *ice)
@@ -114,9 +126,26 @@ static bool qcom_ice_check_supported(struct qcom_ice *ice)
return false;
}
+ /* HWKM version v2 is present from ICE 3.2.1 onwards while version v1
+ * is present only in ICE 3.2.0.
+ */
+ if (major == 4 ||
+ (major == 3 && (minor >= 3 || (minor == 2 && step >= 1))))
+ ice->hwkm_version = QCOM_ICE_HWKM_V2;
+ else if ((major == 3) && (minor == 2))
+ ice->hwkm_version = QCOM_ICE_HWKM_V1;
+ else
+ ice->hwkm_version = 0;
+
dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
major, minor, step);
+ if (!ice->hwkm_version)
+ dev_info(dev, "QC Hard Ware Key Manager (HWKM) not supported\n");
+ else
+ dev_info(dev, "QC Hard Ware Key Manager (HWKM) version v%d\n",
+ ice->hwkm_version);
+
/* If fuses are blown, ICE might not work in the standard way. */
regval = qcom_ice_readl(ice, QCOM_ICE_REG_FUSE_SETTING);
if (regval & (QCOM_ICE_FUSE_SETTING_MASK |
@@ -131,19 +160,18 @@ static bool qcom_ice_check_supported(struct qcom_ice *ice)
* v3.2.1 and later have HWKM v2. ICE v3.2.0 has HWKM v1. Earlier ICE
* versions don't have HWKM at all. However, for HWKM to be fully
* usable by Linux, the TrustZone software also needs to support certain
- * SCM calls including the ones to generate and prepare keys. That
- * effectively makes the earliest supported SoC be SM8650, which has
- * HWKM v2. Therefore, this driver doesn't include support for HWKM v1,
- * and it checks for the SCM call support before it decides to use HWKM.
+ * SCM calls including the ones to generate and prepare keys. Support
+ * for these SCM calls is present for SoCs with HWKM v2 and is being
+ * added for SoCs with HWKM v1 as well but not every SoC with HWKM v1
+ * currently supports this. So, this driver checks for the SCM call
+ * support before it decides to use HWKM.
*
* Also, since HWKM and legacy mode are mutually exclusive, and
* ICE-capable storage driver(s) need to know early on whether to
* advertise support for raw keys or wrapped keys, HWKM cannot be used
* unconditionally. A module parameter is used to opt into using it.
*/
- if ((major >= 4 ||
- (major == 3 && (minor >= 3 || (minor == 2 && step >= 1)))) &&
- qcom_scm_has_wrapped_key_support()) {
+ if (ice->hwkm_version && qcom_scm_has_wrapped_key_support()) {
if (qcom_ice_use_wrapped_keys) {
dev_info(dev, "Using HWKM. Supporting wrapped keys only.\n");
ice->use_hwkm = true;
@@ -212,8 +240,8 @@ static int qcom_ice_wait_bist_status(struct qcom_ice *ice)
(QCOM_ICE_HWKM_KT_CLEAR_DONE |
QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE |
QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE |
- QCOM_ICE_HWKM_CRYPTO_BIST_DONE_V2 |
- QCOM_ICE_HWKM_BIST_DONE_V2)) {
+ QCOM_ICE_HWKM_CRYPTO_BIST_DONE(ice->hwkm_version) |
+ QCOM_ICE_HWKM_BIST_DONE(ice->hwkm_version))) {
dev_err(ice->dev, "HWKM self-test error!\n");
/*
* Too late to revoke use_hwkm here, as it was already
@@ -230,7 +258,7 @@ static void qcom_ice_hwkm_init(struct qcom_ice *ice)
if (!ice->use_hwkm)
return;
- BUILD_BUG_ON(QCOM_ICE_HWKM_WRAPPED_KEY_SIZE >
+ BUILD_BUG_ON(QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version) >
BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE);
/*
* When ICE is in HWKM mode, it only supports wrapped keys.
@@ -238,9 +266,18 @@ static void qcom_ice_hwkm_init(struct qcom_ice *ice)
*
* Put ICE in HWKM mode. ICE defaults to legacy mode.
*/
- regval = qcom_ice_readl(ice, QCOM_ICE_REG_CONTROL);
- regval &= ~QCOM_ICE_LEGACY_MODE_ENABLED;
- qcom_ice_writel(ice, regval, QCOM_ICE_REG_CONTROL);
+ if (ice->hwkm_version == QCOM_ICE_HWKM_V2) {
+ regval = qcom_ice_readl(ice, QCOM_ICE_REG_CONTROL);
+ regval &= ~QCOM_ICE_LEGACY_MODE_ENABLED;
+ qcom_ice_writel(ice, regval, QCOM_ICE_REG_CONTROL);
+ } else if (ice->hwkm_version == QCOM_ICE_HWKM_V1) {
+ regval = qcom_ice_readl(ice, QCOM_ICE_REG_HWKM_TZ_KM_CTL);
+ regval &= ~QCOM_ICE_HWKM_ICE_LEGACY_MODE_ENABLED;
+ qcom_ice_writel(ice, regval, QCOM_ICE_REG_HWKM_TZ_KM_CTL);
+ } else {
+ dev_err(ice->dev, "Invalid HWKM version\n");
+ return;
+ }
/* Disable CRC checks. This HWKM feature is not used. */
qcom_ice_writel(ice, QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL,
@@ -298,7 +335,8 @@ EXPORT_SYMBOL_GPL(qcom_ice_suspend);
static unsigned int translate_hwkm_slot(struct qcom_ice *ice, unsigned int slot)
{
- return slot * 2;
+ /* The slot offset depends upon HWKM version */
+ return (ice->hwkm_version == QCOM_ICE_HWKM_V1) ? (slot) : (slot * 2);
}
static int qcom_ice_program_wrapped_key(struct qcom_ice *ice, unsigned int slot,
@@ -451,11 +489,12 @@ int qcom_ice_generate_key(struct qcom_ice *ice,
{
int err;
- err = qcom_scm_generate_ice_key(lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE);
+ err = qcom_scm_generate_ice_key(lt_key,
+ QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version));
if (err)
return err;
- return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE;
+ return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version);
}
EXPORT_SYMBOL_GPL(qcom_ice_generate_key);
@@ -478,13 +517,13 @@ int qcom_ice_prepare_key(struct qcom_ice *ice,
int err;
err = qcom_scm_prepare_ice_key(lt_key, lt_key_size,
- eph_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE);
+ eph_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version));
if (err == -EIO || err == -EINVAL)
err = -EBADMSG; /* probably invalid key */
if (err)
return err;
- return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE;
+ return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version);
}
EXPORT_SYMBOL_GPL(qcom_ice_prepare_key);
@@ -506,11 +545,11 @@ int qcom_ice_import_key(struct qcom_ice *ice,
int err;
err = qcom_scm_import_ice_key(raw_key, raw_key_size,
- lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE);
+ lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version));
if (err)
return err;
- return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE;
+ return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version);
}
EXPORT_SYMBOL_GPL(qcom_ice_import_key);
--
2.34.1
Powered by blists - more mailing lists