From patchwork Tue Jun 18 00:37:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Sam Protsenko X-Patchwork-Id: 13701582 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A3006C2BB9A for ; Tue, 18 Jun 2024 00:38:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=HF3yj9NB+f1P6unzjOcT62NKC0TjmglEhNnCfK/YhxY=; b=FDACml3c1MoEQLv6JUAgoYrTLw PcslMvDs4zLGNZOBWFIrFmpRcO8EjMQ1DndcMgtt9DNrNFUoiUqL1qOrr9XIW2hsHpOoxg9ThcVax 4Da3ku45xk59llPMK/0d3iDeUCtIayTCTMDGHIdqKxrXjV54TRUbV5ThJnyV9LE4ay3p8KtUx2NOJ z36ynn5eD5/fHXFVUnEqB+M/klCal+Wx6oCTmioRpYI8UD5fXwcotKo9Cb1bFqTI7TDBjRCjDhEqw ZQStsQbkkXED2zaha66I7Xfx//OvCMpyhwgLFr1CWP7SeLBCpekMUpyk8Md5x8sAdeR8sgW+FdkM2 nJAC0Ung==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1sJMrH-0000000D4sb-03QS; Tue, 18 Jun 2024 00:37:59 +0000 Received: from mail-ot1-x335.google.com ([2607:f8b0:4864:20::335]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1sJMr6-0000000D4mR-0snq for linux-arm-kernel@lists.infradead.org; Tue, 18 Jun 2024 00:37:50 +0000 Received: by mail-ot1-x335.google.com with SMTP id 46e09a7af769-6f855b2499cso2741080a34.1 for ; Mon, 17 Jun 2024 17:37:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1718671067; x=1719275867; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HF3yj9NB+f1P6unzjOcT62NKC0TjmglEhNnCfK/YhxY=; b=pz8gfOMxwptxOfgobh38bHBnuu1vcPLPty3QWwxM1GKHRNe+OJw7n+yRdIYPPiP5Xl o8l/91Ick+1U3EI3KVOw5vPAGUad0Xl/Ft4ZUYNMblMTzAyJ8Ox/C8GTQ+hK/lZa/84b Csw9cKa2JQttchLLFhUK2H5FqQdtLO8sEHroMt/xlvIeY+/UpHXVj2yxIByOR6bIhUKR KNspGyDUnLkVmlPRVBBpQJsOS6Tp9GqVMTr6H/jwHMKjUyGidQPL8rBng8W4wvVd9NxN /lQR34EKUffJ5eiaKPi181XzDeX1wMybDjGVooXSEu7WpaJV/pu515M9FUndesnc3DSe 1jtA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718671067; x=1719275867; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HF3yj9NB+f1P6unzjOcT62NKC0TjmglEhNnCfK/YhxY=; b=BXXY8CV0YBZKkwIEkJ8gTv4rkAAPm6mUPF7l3GQFpFu9j64FB2MI6aK8e1zHNMgXbM 5Z74PKDMr6C/MlbxL+x44WdE/lzbvLRdFR+YP8BHpp5zkKCxakXk9BjxiPbQca8WugXA YbGpcSfd0aQfXNym+e+G4e9gnHJgc4ItufMH6UwSMLtlr3QIonZT86LcSPyvzLUC6Wcy 2RYUCLT+w/zJoRZNaC4/KEj1HT9shOnUPYG0HyvZcTFjwF4x+R7WbrAOwTTLPU2DdJRk 7nAvNAl8s4tthvn4sqemr4Hm/lHLX0JqCp+cYlnw7gzrem1B3n2xfhiRiACzTERvYKi6 t5xg== X-Forwarded-Encrypted: i=1; AJvYcCWb9drWEiGUooT+d1hcnJ/SMDkiQiw4hM+7gRYpWz8OSVuf9oQJB4kcmp4NorTEwEiyy3R0ZoiTO9Bq71fxLsMLNbEpqSAyBMom2Va7iL32QMRSrxA= X-Gm-Message-State: AOJu0YzqSTA2ghTbF882uKCX16PHJxU1wbFHVN6Vc/EqrvdzbeUSbhMm wUWiVl9BFW4l24/TuwqMOeuRZngNDkO/JntVvXXdr5FRK05jXOFRMdgf2P4xXmk= X-Google-Smtp-Source: AGHT+IHKCaUtR8KPhYQJdoRvRQDarGdrRA43rA9XABMCQXk9wPvcC+mPa8iPETKzce2FCdEkupbjPA== X-Received: by 2002:a05:6830:1be2:b0:6f9:ce8e:5da1 with SMTP id 46e09a7af769-6fb9364aa32mr12434212a34.26.1718671067124; Mon, 17 Jun 2024 17:37:47 -0700 (PDT) Received: from localhost ([136.62.192.75]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-6fb5afab833sm1686856a34.10.2024.06.17.17.37.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 17:37:46 -0700 (PDT) From: Sam Protsenko To: =?utf-8?q?=C5=81ukasz_Stelmach?= , Krzysztof Kozlowski , Rob Herring , Conor Dooley Cc: Olivia Mackall , Herbert Xu , Alim Akhtar , linux-samsung-soc@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 5/7] hwrng: exynos: Add SMC based TRNG operation Date: Mon, 17 Jun 2024 19:37:41 -0500 Message-Id: <20240618003743.2975-6-semen.protsenko@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240618003743.2975-1-semen.protsenko@linaro.org> References: <20240618003743.2975-1-semen.protsenko@linaro.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240617_173748_350852_9DF98AF4 X-CRM114-Status: GOOD ( 24.31 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On some Exynos chips like Exynos850 the access to Security Sub System (SSS) registers is protected with TrustZone, and therefore only possible from EL3 monitor software. The Linux kernel is running in EL1, so the only way for the driver to obtain TRNG data is via SMC calls to EL3 monitor. Implement such SMC operation and use it when QUIRK_SMC is set in the corresponding chip driver data. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski --- drivers/char/hw_random/exynos-trng.c | 130 ++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 10 deletions(-) diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c index 4520a280134c..98b7a8ebb909 100644 --- a/drivers/char/hw_random/exynos-trng.c +++ b/drivers/char/hw_random/exynos-trng.c @@ -10,6 +10,7 @@ * Krzysztof Kozłowski */ +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #define EXYNOS_TRNG_CLKDIV 0x0 @@ -44,16 +46,40 @@ #define EXYNOS_TRNG_FIFO_LEN 8 #define EXYNOS_TRNG_CLOCK_RATE 500000 +#define QUIRK_SMC BIT(0) + +#define EXYNOS_SMC_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_SIP, \ + func_num) + +/* SMC command for DTRNG access */ +#define SMC_CMD_RANDOM EXYNOS_SMC_CALL_VAL(0x1012) + +/* SMC_CMD_RANDOM: arguments */ +#define HWRNG_INIT 0x0 +#define HWRNG_EXIT 0x1 +#define HWRNG_GET_DATA 0x2 +#define HWRNG_RESUME 0x3 + +/* SMC_CMD_RANDOM: return values */ +#define HWRNG_RET_OK 0x0 +#define HWRNG_RET_RETRY_ERROR 0x2 + +#define HWRNG_MAX_TRIES 100 + struct exynos_trng_dev { struct device *dev; void __iomem *mem; struct clk *clk; /* operating clock */ struct clk *pclk; /* bus clock */ struct hwrng rng; + unsigned long quirks; }; -static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max, - bool wait) +static int exynos_trng_do_read_reg(struct hwrng *rng, void *data, size_t max, + bool wait) { struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv; int val; @@ -70,7 +96,40 @@ static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max, return max; } -static int exynos_trng_init(struct hwrng *rng) +static int exynos_trng_do_read_smc(struct hwrng *rng, void *data, size_t max, + bool wait) +{ + struct arm_smccc_res res; + u32 *buf = data; + unsigned int copied = 0; + int tries = 0; + + while (copied < max) { + arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_GET_DATA, 0, 0, 0, 0, 0, 0, + &res); + switch (res.a0) { + case HWRNG_RET_OK: + *buf++ = res.a2; + *buf++ = res.a3; + copied += 8; + tries = 0; + break; + case HWRNG_RET_RETRY_ERROR: + if (!wait) + return copied; + if (++tries >= HWRNG_MAX_TRIES) + return copied; + cond_resched(); + break; + default: + return -EIO; + } + } + + return copied; +} + +static int exynos_trng_init_reg(struct hwrng *rng) { struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv; unsigned long sss_rate; @@ -103,6 +162,17 @@ static int exynos_trng_init(struct hwrng *rng) return 0; } +static int exynos_trng_init_smc(struct hwrng *rng) +{ + struct arm_smccc_res res; + + arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_INIT, 0, 0, 0, 0, 0, 0, &res); + if (res.a0 != HWRNG_RET_OK) + return -EIO; + + return 0; +} + static int exynos_trng_probe(struct platform_device *pdev) { struct exynos_trng_dev *trng; @@ -112,21 +182,29 @@ static int exynos_trng_probe(struct platform_device *pdev) if (!trng) return ret; + platform_set_drvdata(pdev, trng); + trng->dev = &pdev->dev; + + trng->quirks = (unsigned long)device_get_match_data(&pdev->dev); + trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev), GFP_KERNEL); if (!trng->rng.name) return ret; - trng->rng.init = exynos_trng_init; - trng->rng.read = exynos_trng_do_read; trng->rng.priv = (unsigned long)trng; - platform_set_drvdata(pdev, trng); - trng->dev = &pdev->dev; + if (trng->quirks & QUIRK_SMC) { + trng->rng.init = exynos_trng_init_smc; + trng->rng.read = exynos_trng_do_read_smc; + } else { + trng->rng.init = exynos_trng_init_reg; + trng->rng.read = exynos_trng_do_read_reg; - trng->mem = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(trng->mem)) - return PTR_ERR(trng->mem); + trng->mem = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(trng->mem)) + return PTR_ERR(trng->mem); + } pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev); @@ -190,6 +268,13 @@ static void exynos_trng_remove(struct platform_device *pdev) { struct exynos_trng_dev *trng = platform_get_drvdata(pdev); + if (trng->quirks & QUIRK_SMC) { + struct arm_smccc_res res; + + arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_EXIT, 0, 0, 0, 0, 0, 0, + &res); + } + clk_disable_unprepare(trng->clk); clk_disable_unprepare(trng->pclk); @@ -199,6 +284,16 @@ static void exynos_trng_remove(struct platform_device *pdev) static int exynos_trng_suspend(struct device *dev) { + struct exynos_trng_dev *trng = dev_get_drvdata(dev); + struct arm_smccc_res res; + + if (trng->quirks & QUIRK_SMC) { + arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_EXIT, 0, 0, 0, 0, 0, 0, + &res); + if (res.a0 != HWRNG_RET_OK) + return -EIO; + } + pm_runtime_put_sync(dev); return 0; @@ -206,6 +301,7 @@ static int exynos_trng_suspend(struct device *dev) static int exynos_trng_resume(struct device *dev) { + struct exynos_trng_dev *trng = dev_get_drvdata(dev); int ret; ret = pm_runtime_resume_and_get(dev); @@ -214,6 +310,20 @@ static int exynos_trng_resume(struct device *dev) return ret; } + if (trng->quirks & QUIRK_SMC) { + struct arm_smccc_res res; + + arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_RESUME, 0, 0, 0, 0, 0, 0, + &res); + if (res.a0 != HWRNG_RET_OK) + return -EIO; + + arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_INIT, 0, 0, 0, 0, 0, 0, + &res); + if (res.a0 != HWRNG_RET_OK) + return -EIO; + } + return 0; }