From patchwork Thu Jun 21 15:17:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Timur Tabi X-Patchwork-Id: 10480033 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 96BC360230 for ; Thu, 21 Jun 2018 15:19:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 80CAE28FDC for ; Thu, 21 Jun 2018 15:19:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7542A2902B; Thu, 21 Jun 2018 15:19:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0EBAE28FDC for ; Thu, 21 Jun 2018 15:19:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=zxucMXjkTnEEVpkEKos/PVvWnr9x4G8YphyknSEPIt4=; b=qsu qGcmrGfBNib2YrIunQPtj/Q0RLrMDyi+0NjdXAgGHikxIQ1fMwRefvdkxr+/tG86610VEZ4d0uubn ByrNBrgRwabun/FPlYBZIBbUTs5LnbFfRHi7fkU4ntJLn7YgDMs6cjO0k9DNQLG+cdkvmoKEmMPgD wM1CT+WvMOAGc76ivShXmQfWN8XjrJg2epJRggrspJVnm8jllyaybXhuUPhDqU32GOMxASYsh3CnK KJU3MLoFh3iJO+RMyZIGVPp7TNKX5jtXZqOzFRBnUtB9TuS/goVLOp1PEHK2oGdWjlsdYFUKpElS+ 89NcXIBE51EQCLP1edBle/TSl3UMU2A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fW1Mc-0000YL-2C; Thu, 21 Jun 2018 15:19:10 +0000 Received: from smtp.codeaurora.org ([198.145.29.96]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fW1Lg-00009O-6v for linux-arm-kernel@lists.infradead.org; Thu, 21 Jun 2018 15:18:47 +0000 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 2613B605FD; Thu, 21 Jun 2018 15:18:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1529594281; bh=sDl8k6lHWQkQscldb4BI5/lpVxCdVvu2WK31W5HYWDg=; h=From:To:Cc:Subject:Date:From; b=aWDYdxM1JjwbA75IldU1QB8YwQ/4RLcPRJ69g9DCEWuWdQIvFbCUZnIQPtdSv/lhr a2r+6MOKFCEdCM8iM1oR7lwX7hhu6qvEmguDnhyGDFejKGSA77YIINNF9YdLGi780s 9iCzadCML9TaRHN3fWjQHbTX+gbIcgA/0Yl/Bzu0= Received: from timur-ubuntu.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: timur@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 8A2D660275; Thu, 21 Jun 2018 15:17:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1529594280; bh=sDl8k6lHWQkQscldb4BI5/lpVxCdVvu2WK31W5HYWDg=; h=From:To:Cc:Subject:Date:From; b=J4aJq2WE/Zs264Ko9WPXAg/1zTuMKUPEEzLgJ6z8/njg4oZFNJuvKUAalhF4fweff BTW2j8yrEPv4c096HjzoFJAzACgMgw+5CX11BIHZb8X4O8DjW6gZiutFNI/I+dbKwy 1X9aFzcM0rTYFRTE+n9eFoeTIGWyvzfjisGBENlE= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 8A2D660275 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=timur@codeaurora.org From: Timur Tabi To: linux-arm-kernel@lists.infradead.org, linux-crypto@vger.kernel.org, vinod.koul@linaro.org, Matt Mackall , swboyd@chromium.org, linux-arm-msm@vger.kernel.org, timur@kernel.org Subject: [PATCH 1/2] hwrng: msm: add a spinlock and support for blocking reads Date: Thu, 21 Jun 2018 10:17:55 -0500 Message-Id: <1529594276-12210-1-git-send-email-timur@codeaurora.org> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180621_081812_337766_9B9315EB X-CRM114-Status: GOOD ( 19.42 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: timur@codeaurora.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The hwrng.read callback includes a boolean parameter called 'wait' which indicates whether the function should block and wait for more data. When 'wait' is true, the driver spins on the DATA_AVAIL bit or until a reasonable timeout. The timeout can occur if there is a heavy load on reading the PRNG. The same code also needs a spinlock to protect against race conditions. If multiple cores hammer on the PRNG, it's possible for a race condition to occur between reading the status register and reading the data register. Add a spinlock to protect against that. 1. Core 1 reads status register, shows data is available. 2. Core 2 also reads status register, same result 3. Core 2 reads data register, depleting all entropy 4. Core 1 reads data register, which returns 0 Signed-off-by: Timur Tabi --- drivers/char/hw_random/msm-rng.c | 57 +++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c index 841fee845ec9..44580588b938 100644 --- a/drivers/char/hw_random/msm-rng.c +++ b/drivers/char/hw_random/msm-rng.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include /* Device specific register offsets */ #define PRNG_DATA_OUT 0x0000 @@ -35,10 +37,22 @@ #define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4) #define WORD_SZ 4 +/* + * Normally, this would be the maximum time it takes to refill the FIFO, + * after a read. Under heavy load, tests show that this delay is either + * below 50us or above 2200us. The higher value is probably what happens + * when entropy is completely depleted. + * + * Since we don't want to wait 2ms in a spinlock, set the timeout to the + * lower value. Under extreme situations, that timeout can extend to 100us. + */ +#define TIMEOUT 50 + struct msm_rng { void __iomem *base; struct clk *clk; struct hwrng hwrng; + spinlock_t lock; }; #define to_msm_rng(p) container_of(p, struct msm_rng, hwrng) @@ -96,11 +110,39 @@ static int msm_rng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) /* read random data from hardware */ do { - val = readl_relaxed(rng->base + PRNG_STATUS); - if (!(val & PRNG_STATUS_DATA_AVAIL)) - break; + spin_lock(&rng->lock); + + /* + * First check the status bit. If 'wait' is true, then wait + * up to TIMEOUT microseconds for data to be available. + */ + if (wait) { + int ret; + + ret = readl_poll_timeout_atomic(rng->base + PRNG_STATUS, + val, val & PRNG_STATUS_DATA_AVAIL, 0, TIMEOUT); + if (ret) { + /* Timed out */ + spin_unlock(&rng->lock); + break; + } + } else { + val = readl_relaxed(rng->base + PRNG_STATUS); + if (!(val & PRNG_STATUS_DATA_AVAIL)) { + spin_unlock(&rng->lock); + break; + } + } val = readl_relaxed(rng->base + PRNG_DATA_OUT); + spin_unlock(&rng->lock); + + /* + * Zero is technically a valid random number, but it's also + * the value returned if the PRNG is not enabled properly. + * To avoid accidentally returning all zeros, treat it as + * invalid and just return what we've already read. + */ if (!val) break; @@ -148,10 +190,11 @@ static int msm_rng_probe(struct platform_device *pdev) if (IS_ERR(rng->clk)) return PTR_ERR(rng->clk); - rng->hwrng.name = KBUILD_MODNAME, - rng->hwrng.init = msm_rng_init, - rng->hwrng.cleanup = msm_rng_cleanup, - rng->hwrng.read = msm_rng_read, + rng->hwrng.name = KBUILD_MODNAME; + rng->hwrng.init = msm_rng_init; + rng->hwrng.cleanup = msm_rng_cleanup; + rng->hwrng.read = msm_rng_read; + spin_lock_init(&rng->lock); ret = devm_hwrng_register(&pdev->dev, &rng->hwrng); if (ret) {