[PATCH] crypto: caam - check jr permissions before probing

From: Andrey Zhizhikin
Date: Thu Nov 04 2021 - 12:21:40 EST


Job Rings can be set to be exclusively used by TrustZone which makes the
access to those rings only possible from Secure World. This access
separation is defined by setting bits in CAAM JRxDID_MS register. Once
reserved to be owned by TrustZone, this Job Ring becomes unavailable for
the Kernel. This reservation is performed early in the boot process,
even before the Kernel starts, which leads to unavailability of the HW
at the probing stage. Moreover, the reservation can be done for any Job
Ring and is not under control of the Kernel. The only condition that
remains is: at least one Job Ring should be made available for the NS
world.

Current implementation lists Job Rings as child nodes of CAAM driver,
and tries to perform probing on those regardless of whether JR HW is
accessible or not.

This leads to the following error while probing:
[ 1.509894] caam 30900000.crypto: job rings = 3, qi = 0
[ 1.525201] caam_jr 30901000.jr: failed to flush job ring 0
[ 1.525214] caam_jr: probe of 30901000.jr failed with error -5

Implement a dynamic mechanism to identify which Job Ring is actually
marked as owned by TrustZone, and fail the probing of those child nodes
with -ENODEV.

Signed-off-by: Andrey Zhizhikin <andrey.zhizhikin@xxxxxxxxxxxxxxxxxxxx>
---
drivers/crypto/caam/ctrl.c | 18 ++++++++++++------
drivers/crypto/caam/intern.h | 1 +
drivers/crypto/caam/jr.c | 17 +++++++++++++++++
drivers/crypto/caam/regs.h | 8 +++++---
4 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index ca0361b2dbb0..c48506a02340 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -805,12 +805,18 @@ static int caam_probe(struct platform_device *pdev)
for_each_available_child_of_node(nprop, np)
if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
- ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
- ((__force uint8_t *)ctrl +
- (ring + JR_BLOCK_NUMBER) *
- BLOCK_OFFSET
- );
- ctrlpriv->total_jobrs++;
+ /* Check if the JR is not owned exclusively by TZ */
+ if (!((rd_reg32(&ctrl->jr_mid[ring].liodn_ms)) &
+ (MSTRID_LOCK_TZ_OWN | MSTRID_LOCK_PRIM_TZ))) {
+ ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
+ ((__force uint8_t *)ctrl +
+ (ring + JR_BLOCK_NUMBER) *
+ BLOCK_OFFSET
+ );
+ /* Indicate that this JR is available for NS */
+ ctrlpriv->jobr_ns_flags |= BIT(ring);
+ ctrlpriv->total_jobrs++;
+ }
ring++;
}

diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index 7d45b21bd55a..2919af55dbfe 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -91,6 +91,7 @@ struct caam_drv_private {
* or from register-based version detection code
*/
u8 total_jobrs; /* Total Job Rings in device */
+ u8 jobr_ns_flags; /* Flags for each Job Ring if it is not owned by TZ*/
u8 qi_present; /* Nonzero if QI present in device */
u8 mc_en; /* Nonzero if MC f/w is active */
int secvio_irq; /* Security violation interrupt number */
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 7f2b1101f567..a260981e0843 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -511,10 +511,27 @@ static int caam_jr_probe(struct platform_device *pdev)
struct device_node *nprop;
struct caam_job_ring __iomem *ctrl;
struct caam_drv_private_jr *jrpriv;
+ struct caam_drv_private *caamctrlpriv;
static int total_jobrs;
struct resource *r;
int error;

+ /* Before we proceed with the JR device probing, verify
+ * that the job ring itself is available to Non-Secure world.
+ * If the JR is owned exclusively by TZ - we should not even
+ * process it further.
+ */
+ caamctrlpriv = dev_get_drvdata(pdev->dev.parent);
+ if (!(caamctrlpriv->jobr_ns_flags & BIT(total_jobrs))) {
+ /* This job ring is marked to be exclusively used by TZ,
+ * do not proceed with probing as the HW block is inaccessible.
+ * Increment total seen JR devices since it is used as the index
+ * into verification and fail probing for this node.
+ */
+ total_jobrs++;
+ return -ENODEV;
+ }
+
jrdev = &pdev->dev;
jrpriv = devm_kzalloc(jrdev, sizeof(*jrpriv), GFP_KERNEL);
if (!jrpriv)
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index 3738625c0250..8ade617f9e65 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -445,10 +445,12 @@ struct caam_perfmon {
};

/* LIODN programming for DMA configuration */
-#define MSTRID_LOCK_LIODN 0x80000000
-#define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */
+#define MSTRID_LOCK_LIODN BIT(31)
+#define MSTRID_LOCK_MAKETRUSTED BIT(16) /* only for JR: masterid */
+#define MSTRID_LOCK_TZ_OWN BIT(15) /* only for JR: owned by TZ */
+#define MSTRID_LOCK_PRIM_TZ BIT(4) /* only for JR: Primary TZ */

-#define MSTRID_LIODN_MASK 0x0fff
+#define MSTRID_LIODN_MASK GENMASK(11, 0)
struct masterid {
u32 liodn_ms; /* lock and make-trusted control bits */
u32 liodn_ls; /* LIODN for non-sequence and seq access */

base-commit: 8a796a1dfca2780321755033a74bca2bbe651680
--
2.25.1