Thread (24 messages) 24 messages, 4 authors, 2022-01-27

Re: [PATCH 01/10] soc: qcom: new common library for ICE functionality

From: Eric Biggers <ebiggers@kernel.org>
Date: 2021-12-14 00:20:53
Also in: linux-arm-msm, linux-fscrypt, linux-mmc, linux-scsi

On Mon, Dec 06, 2021 at 02:57:16PM -0800, Gaurav Kashyap wrote:
Add a new library which congregates all the ICE
functionality so that all storage controllers containing
ICE can utilize it.
In commit messages and comments, please spell out "Inline Crypto Engine (ICE)"
the first time it appears, so that people know what ICE means.
quoted hunk ↗ jump to hunk
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 79b568f82a1c..a900f5ab6263 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"
Since this is a library, it shouldn't be user-selectable, but rather just be
selected by the other options that need it.  Putting a string after "tristate"
makes it user-selectable; the string is the prompt string.  The line should just
be "tristate", without a string afterwards.
quoted hunk ↗ jump to hunk
diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c
new file mode 100644
index 000000000000..0c5b529201c5
--- /dev/null
+++ b/drivers/soc/qcom/qti-ice-common.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common ICE library for storage encryption.
+ *
+ * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved.
+ */
+
+#include <linux/qti-ice-common.h>
+#include <linux/module.h>
+#include <linux/qcom_scm.h>
+#include <linux/delay.h>
+#include "qti-ice-regs.h"
+
+#define QTI_ICE_MAX_BIST_CHECK_COUNT    100
+#define QTI_AES_256_XTS_KEY_RAW_SIZE	64
+
+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;
+	}
For log messages associated with a device, the dev_*() functions should be used
instead of pr_*().  How about including the relevant 'struct device *' in the
struct ice_mmio_data?

This comment applies to everywhere in qti-ice-common that is logging anything.
+/**
+ * qti_ice_init() - Initialize ICE functionality
+ * @ice_mmio_data: contains ICE register mapping for i/o
+ *
+ * Initialize ICE by checking the version for ICE support and
+ * also checking the fuses blown.
+ *
+ * Return: 0 on success; -EINVAL on failure.
+ */
+int qti_ice_init(const struct ice_mmio_data *mmio)
+{
+	if (!qti_ice_supported(mmio))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qti_ice_init);
Be more specific about what "failure" means here.  It means that the driver
doesn't support the ICE hardware, right?  -ENODEV would be a more appropriate
error code for this.  -EINVAL is a very generic error.
+static void qti_ice_low_power_and_optimization_enable(
+				const struct ice_mmio_data *mmio)
+{
+	u32 regval = qti_ice_readl(mmio->ice_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->ice_mmio, regval, QTI_ICE_REGS_ADVANCED_CONTROL);
+	/* Memory barrier - to ensure write completion before next transaction */
+	wmb();
+}
This part changed slightly from the original code in
drivers/scsi/ufs/ufs-qcom-ice.c and drivers/mmc/host/sdhci-msm.c.  What is the
reason for these changes?  To be fair, I can't properly explain this part of the
original code; I just did what some existing ICE code was doing.  But if it
wasn't the correct or best way, it would be super useful to understand *why*
this different version is really the correct/best way.

Also note that the line "regval |= 0x7000;" is redundant.
+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;
+}
The copy of this in drivers/mmc/host/sdhci-msm.c is a bit nicer in that it uses
the readl_poll_timeout() helper function, and it has a longer comment explaining
it.  So I think you should use that version rather than the UFS version.
+/**
+ * qti_ice_keyslot_program() - Program a key to an ICE slot
+ * @ice_mmio_data: contains ICE register mapping for i/o
+ * @crypto_key: key to be program, this can be wrapped or raw
+ * @crypto_key_size: size of the key to be programmed
+ * @slot: the keyslot at which the key should be programmed.
+ * @data_unit_mask: mask for the dun which is part of the
+ *                  crypto configuration.
+ * @capid: capability index indicating the algorithm for the
+ *         crypto configuration
+ *
+ * Program the passed in key to a slot in ICE.
+ * The key that is passed in can either be a raw key or wrapped.
+ * In both cases, due to access control of ICE for Qualcomm chipsets,
+ * a scm call is used to program the key into ICE from trustzone.
+ * Trustzone can differentiate between raw and wrapped keys.
How does TrustZone differentiate between raw and wrapped keys?  I thought you
had mentioned that only one is supported at a time on a particular SoC.
+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[QTI_AES_256_XTS_KEY_RAW_SIZE];
+		u32 words[QTI_AES_256_XTS_KEY_RAW_SIZE / sizeof(u32)];
+	} key;
+
+	memcpy(key.bytes, crypto_key, crypto_key_size);
This is assuming that wrapped keys aren't longer than raw AES-256-XTS keys,
which isn't necessarily true.
+#define qti_ice_writel(mmio, val, reg)		\
+	writel_relaxed((val), mmio + (reg))
+#define qti_ice_readl(mmio, reg)		\
+	readl_relaxed(mmio + (reg))
Previously, writel() and readl() were used instead of writel_relaxed() and
readl_relaxed().  What is the reason for this change?  My understanding is that
the *_relaxed() functions are harder to use correctly, so they shouldn't be used
unless it's been carefully thought through and the extra performance is needed.

- Eric
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help