From patchwork Fri May 24 16:26:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 165138 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp3814175ili; Fri, 24 May 2019 09:27:41 -0700 (PDT) X-Google-Smtp-Source: APXvYqy32z2cfqsMRSptOnBDDxgXwwJt2CwpPc99CqmOHBPYBT+mZmnsRR5V51ga5Cd8FkC4nn1I X-Received: by 2002:a62:d286:: with SMTP id c128mr114307194pfg.159.1558715260974; Fri, 24 May 2019 09:27:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558715260; cv=none; d=google.com; s=arc-20160816; b=juDeA+ll5ChnSif+mDEZiNupUpfvjCE2AiWVBQCQvcTmUtMVx3bCfmaRDVcn6+k3Rw KwCIuWJKH49GpTSRp8pfXojeuqTqD6UiJ4sPYWmR4xFZv5BCpfEm533xrJ8lYp8nWDcA TeE5J3Uhe1UMYh/Upj0CwAcTpSuizrDSPI8aO/+Tlqo+bQ7pa0JxUSDFC9QWVlSfu6Fy +RSvP0Uxh+iJSZS0QM6qkR2LUTeaW8Wb72/aLS7NJCtUyfXlP814p7rG0TXA3jxH+L8q wNBL8EyM4FGmNg9gw20v0lUiXHPXAbg33s0PWhKRES9jYZf+UTiP4ZQ2fRG+bC5dD2zd nQhw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=feMTK1ALuDcB6ANRh60ilE7eIkZ7WZWllXS4rnIjAYY=; b=pityjkls+uXdBKUjWWomflyj41c++aiEEdTpJrIZMkpb3mS6if1SnlwxHocxTdWjCG nEzbGWe28LP7l/xBMMwu/4FgV3E/t4R3/2b+Y+TVfS0xJVdG5ke+LVBeUHwNbAPvpnNc yG7wSAwE78d6EnyGxRVOwlaY6TResfRDbAwvmfEApQQVWFtNUixl/KFyi0zypOxxLSC2 i7s8qaXsQxqb2Cdy1FJdkyJ32EUx+qEq0qF2wErCEvy5a9rAahugGutYvD1bvfNzCfyj VXC5yQ7dVRsmlIAr0dhUfm9BTFUFU+QK1KwIQ/LtojxMPShkPRsACdW71l+z7XkpNhNF 1oMA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=etyGkcer; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r69si4906966pgr.120.2019.05.24.09.27.40; Fri, 24 May 2019 09:27:40 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=etyGkcer; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390318AbfEXQ1k (ORCPT + 7 others); Fri, 24 May 2019 12:27:40 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:55693 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390623AbfEXQ1j (ORCPT ); Fri, 24 May 2019 12:27:39 -0400 Received: by mail-wm1-f66.google.com with SMTP id x64so9993953wmb.5 for ; Fri, 24 May 2019 09:27:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=feMTK1ALuDcB6ANRh60ilE7eIkZ7WZWllXS4rnIjAYY=; b=etyGkcerFFK63wVJPJo3fAK6GJwu4arL3yT6oqa6tEDzNWodmPXx8J2hDmjVU+s/62 FtW5cwEZJvReJiIYHfu52g9IpnAl08zsoHEFzpa2JM9Pder9hqhyDJyIZ4NyNThF/tUg rCPo4rXpUSl5n6mc6zDip9MwBZNeqsypfSKfgnSjx21B/wtM9RQIfnPIf0RC/o8zxzrh 2aeIBX35HY3ROFBAKKQc993TzUfCK5nfErFt0nEISY9TOec9UhC5dL4+d1/aoxDfcHuh oiWITzP1MVuIJ/4NVbuD/NRzTqImYz3GpVMkqZU01a9H8Y7kBHgtR0EN0DHrk43ROwar DHJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=feMTK1ALuDcB6ANRh60ilE7eIkZ7WZWllXS4rnIjAYY=; b=jedrjO7FG/KKZksU8A8PX6WKV0JaNenlZXqKzvpRv1PHhSzO1QlvZKw8oke820kENh tA6Hsv5GrNDt8chWU3LtgPJMlW6Ia8gm4xXS6Ce+nkAQ+2YuyDbkubdwIjAjGEUqYt7Z Z1+Lvo7TwRj/KhJc505tfbuVxy5Hgn5P49plTX/4NRaYSUY3xGiZSkE82XKad1wFaawS wV/8+PoyIrSXTZZqJ3JEWUDWQnGAVhsmnXzp8/1iGX3BK4fdyUXYvM2CNBXQVitmQEsc Ugk5eSYX+Mw/d1t9Zdjf5hIfU5ZGPxLlWJGGSc+LXjPGeuiXWda38rY4E5L7D05fFMBS fWpQ== X-Gm-Message-State: APjAAAVN9109u0qDsKwzVWEnnnjbkMBjXaRay1Up960+lw6b+mDJYoBk tAmKcvxfmfgY5jX2G6Xf3PqPMQ== X-Received: by 2002:a1c:f507:: with SMTP id t7mr17188238wmh.149.1558715258061; Fri, 24 May 2019 09:27:38 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:2042:d8f2:ded8:fa95]) by smtp.gmail.com with ESMTPSA id l6sm2200320wmi.24.2019.05.24.09.27.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 May 2019 09:27:37 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Ard Biesheuvel , Herbert Xu , Tudor Ambarus , Linus Walleij , Mika Westerberg Subject: [PATCH v2 1/6] i2c: acpi: permit bus speed to be discovered after enumeration Date: Fri, 24 May 2019 18:26:46 +0200 Message-Id: <20190524162651.28189-2-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190524162651.28189-1-ard.biesheuvel@linaro.org> References: <20190524162651.28189-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Currently, the I2C ACPI enumeration code only permits the max bus rate to be discovered before enumerating the slaves on the bus. In some cases, drivers for slave devices may require this information, e.g., some ATmel crypto drivers need to generate a so-called wake token of a fixed duration, regardless of the bus rate. So tweak the code so i2c_acpi_lookup_speed() is able to obtain this information after enumeration as well. Acked-by: Mika Westerberg Signed-off-by: Ard Biesheuvel --- drivers/i2c/i2c-core-acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) -- 2.20.1 diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 272800692088..7240cc07abb4 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -115,8 +115,7 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, struct list_head resource_list; int ret; - if (acpi_bus_get_status(adev) || !adev->status.present || - acpi_device_enumerated(adev)) + if (acpi_bus_get_status(adev) || !adev->status.present) return -EINVAL; if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) @@ -151,6 +150,9 @@ static int i2c_acpi_get_info(struct acpi_device *adev, lookup.info = info; lookup.index = -1; + if (acpi_device_enumerated(adev)) + return -EINVAL; + ret = i2c_acpi_do_lookup(adev, &lookup); if (ret) return ret; From patchwork Fri May 24 16:26:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 165139 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp3814196ili; Fri, 24 May 2019 09:27:42 -0700 (PDT) X-Google-Smtp-Source: APXvYqx1wPr/yhwTSA9VNhi1ye/jkNPSYJJat61GY0rlo+cbWDSA5IEb+nsLSxxb4shEckX3qT/f X-Received: by 2002:a63:4753:: with SMTP id w19mr33608199pgk.421.1558715261938; Fri, 24 May 2019 09:27:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558715261; cv=none; d=google.com; s=arc-20160816; b=jcY4FWpliEyrYGXmXHdP1cAZwlsjj2dgadtbYjTV+cqBBA1xqOeg4vkWBX7NuGeGvX DoqT1hJtXRloY8ffOB7US2BBgIRdbcX6n8yl3WdRbvQTRCuqN6J6xXy4E0k11naXL24D awfzBOGRf8UdZO30y82Ugbuv+jYRfEeqPTulbn1fSKQR+x9a7uqBpe6QlgNyNylxw8k3 JQLbZeQkTwOoT9EwxpEXKSmJDkQDuwWCO489cbN9c/5vnSj/5TAmHGzfW6X87b6qaeId bX3Txu9cs2WIHRSnT3VPaC5lpf8rW0OWW0xHXnR3VehLZKAB2K041/ZIyziQjWQRbE6w DEvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=OpsVci6NS0D6Bf/3Go8WTx/jss3RyzyovCrA3zpdENw=; b=CSNz8bRm78bzyWSGzshX4i2nxUTpDnqL4KQel+48CqLoA/ZGFOYO/qvM3/uIvfB1w7 yMTe0ivZyW3vwDFuQIOr0MfEBtQIXOP3tZoFcHT705VO5AyUdFbMxxBmmXCwgRuN+qD3 mzaetm1tpXHb4sS9qi7BYjKpXuIoJDICG+OHSb7zDMnZqyl7bEyaBlK7Kpm+Ahv2u0b0 y0pZ/26JF9w3AEoS4prVpMQwIkC7ONP/B0qdrAaF14lyvwjr9wwPvgeuSzGvYq6YCOUX rYrKb/dF8PUbbNkkU5IzMZdcPRgZ78OjsICrZRR6TZgyWZx9sMTBn6L9JRGPq5hOTh7k D6qQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=HTvI2d+K; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r69si4906966pgr.120.2019.05.24.09.27.41; Fri, 24 May 2019 09:27:41 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=HTvI2d+K; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390337AbfEXQ1l (ORCPT + 7 others); Fri, 24 May 2019 12:27:41 -0400 Received: from mail-wr1-f66.google.com ([209.85.221.66]:35545 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390354AbfEXQ1l (ORCPT ); Fri, 24 May 2019 12:27:41 -0400 Received: by mail-wr1-f66.google.com with SMTP id m3so10638847wrv.2 for ; Fri, 24 May 2019 09:27:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=OpsVci6NS0D6Bf/3Go8WTx/jss3RyzyovCrA3zpdENw=; b=HTvI2d+KNikWYtCfyv9ErbQwk9U7SN4mNO0FU31r9IcRKjdCFOiEcfX3ljB4rfrA7R yNGT8C22B7n34+vtuGrX0SE/9+OZk7/YSy95mqEufDiSS3QtYDIWRpn06g5wDqHGarzk VuJ8l5PyKvcxzI+r0snAiTATtmCo0eQ1MjuCyGnc2IOntuJCoLmTOVwwxUzP7T+UZ2/w cKka3JVXHe4l873jUF1KaU6L2vm+jRkc1Abj3aOtTx4wDUfleGbOcmdq29+P0kMlfTtZ bnAErkDLh1l1nPQaT/eKmolaXaddGRqUPRn2sgqfrP9tT+UPY2slGZ8DoELeVWsyuHTu +DYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OpsVci6NS0D6Bf/3Go8WTx/jss3RyzyovCrA3zpdENw=; b=JEaDM/8vE4NA6dHqt0fHmCN4tD8Ja1cEqtNZS5V6FeduYZIphMOlAo91rv5yzlSNDt ecqjhCM5A6JQhvCQcDgp+3e/lSQioYOOeFcWMId0BorZiUSczHF2SFOXKIkSPBVwkWe4 hPWQSyza6URUIvaQL2Yc3kCch521Ce5lYHvaUJfzXJNu7lZgZpIsrdEbROylcZqqE2i5 3/2Mfa+cm3hYF9NLJ1zfwIXU9HeNzpPKADHJ84I+fFlphAFx5Vn1a4miPDdditcSCRc5 QBAfY+kp4LDqjCvfJri4IkYv961uZx69AfzkjGxU4nxqJA0Juz2z+L/lBn3Cg0bz+DPc rNMw== X-Gm-Message-State: APjAAAWuW1fD7GS0q247v7FAHPGpgN0xKTXPBXJiJsxKYlX7DIu53lD0 PUPQFO47IxBgU7LgnRzU18exPw== X-Received: by 2002:adf:edce:: with SMTP id v14mr59665675wro.94.1558715259395; Fri, 24 May 2019 09:27:39 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:2042:d8f2:ded8:fa95]) by smtp.gmail.com with ESMTPSA id l6sm2200320wmi.24.2019.05.24.09.27.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 May 2019 09:27:38 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Ard Biesheuvel , Herbert Xu , Tudor Ambarus , Linus Walleij , Mika Westerberg Subject: [PATCH v2 2/6] crypto: atmel-ecc: add support for ACPI probing on non-AT91 platforms Date: Fri, 24 May 2019 18:26:47 +0200 Message-Id: <20190524162651.28189-3-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190524162651.28189-1-ard.biesheuvel@linaro.org> References: <20190524162651.28189-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The Atmel/Microchip EC508A is a I2C device that could be wired into any platform, and is being used on the Linaro/96boards Secure96 mezzanine adapter. This means it could be found on any platform, even on ones that use ACPI enumeration (via PRP0001 devices). So update the code to enable this use case. This involves tweaking the bus rate discovery code to take ACPI probing into account, which records the maximum bus rate as a property of the slave device. For the atmel-ecc code, this means that the effective bus rate should never exceed the maximum rate, unless we are dealing with buggy firmware. Nonetheless, let's just use the existing plumbing to discover the bus rate and keep the existing logic intact. Signed-off-by: Ard Biesheuvel --- drivers/crypto/Kconfig | 1 - drivers/crypto/atmel-ecc.c | 13 ++++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) -- 2.20.1 Reviewed-by: Linus Walleij diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0af08081e305..97ec8107eeef 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -522,7 +522,6 @@ config CRYPTO_DEV_ATMEL_SHA config CRYPTO_DEV_ATMEL_ECC tristate "Support for Microchip / Atmel ECC hw accelerator" - depends on ARCH_AT91 || COMPILE_TEST depends on I2C select CRYPTO_ECDH select CRC16 diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index ba00e4563ca0..5705348f540f 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -657,11 +657,14 @@ static int atmel_ecc_probe(struct i2c_client *client, return -ENODEV; } - ret = of_property_read_u32(client->adapter->dev.of_node, - "clock-frequency", &bus_clk_rate); - if (ret) { - dev_err(dev, "of: failed to read clock-frequency property\n"); - return ret; + clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); + if (!clk_rate) { + ret = device_property_read_u32(&client->adapter->dev, + "clock-frequency", &bus_clk_rate); + if (ret) { + dev_err(dev, "failed to read clock-frequency property\n"); + return ret; + } } if (bus_clk_rate > 1000000L) { From patchwork Fri May 24 16:26:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 165142 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp3814268ili; Fri, 24 May 2019 09:27:45 -0700 (PDT) X-Google-Smtp-Source: APXvYqyMhqpKauOMlNSU2IjXLRH4QCPen5ALebVfBGXlqshYBcOHvEsY+kiOI0B9NiJvL9idOgxO X-Received: by 2002:a63:5b18:: with SMTP id p24mr63897pgb.452.1558715265299; Fri, 24 May 2019 09:27:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558715265; cv=none; d=google.com; s=arc-20160816; b=b8w4PdUbxDpLrZqB49VTz3M1uvFIntduq0EVkhBH25Rp0igp4fQWpLbPCB8A80jZ2d s51sERJJfXMi57i9BIsAZfi2nUm0VUHQ5yTxEifAtiVEZ0S2ExVcCizOUADoOjvj8NF7 /Hn0ninT9mA5vTCZzQJSf8oSRpprXv5UyuAIlRi0jA5Wfmal9SzjkHv7PasZXkKEo8LN xxGGjz9NzLoVMQzjmsQV26HXmfRr6T1xp5CBvcHh5EpdNHIYj5DLBEOJciSVdRT3+ljz 1+6uz2rM0Whj6E9DI9Uuc9cL4SW8S9TziO3AXjXm57JQFA4p1uEtEPngwHBCQTx5Gf+x 94gg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=o9AkQkRTyfMF48RGZO6XDYSB7I9U5iZYwHLrvW29JTc=; b=tBQg81Uio4ppNI+8Rt7SNWz55knGnNAN4Y/1QIXQDKB3+XnBVQW6KQLLFNs5Z2NW3b g86tCBo/HSPRXhMwF2Q+UoJdHPQb2g/e8Ge618nw9e355dlhRE2X7HgsgsI72UgoAO+I 90inwXm2PpnG4S6sj0zkP02IdpEpkd9zUHAFA+Z8Uxl2Aw8RthA5fCGmY8bxST1QCORS tCDeAM9lqY/nlz526qgDu3HfOEkxer2+HbPrzPCRZJPchpOncv4+xox+k401En6rsWIc 4noXHaPIVBP/4bRvZXlVHwmEd41m3GSvbfzjsFQ3xfE3NOiu0pbtKoSg8pUI2zkcfmJK aWYQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=O+6Yr7OM; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r69si4906966pgr.120.2019.05.24.09.27.44; Fri, 24 May 2019 09:27:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=O+6Yr7OM; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390723AbfEXQ1o (ORCPT + 7 others); Fri, 24 May 2019 12:27:44 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:43920 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390623AbfEXQ1o (ORCPT ); Fri, 24 May 2019 12:27:44 -0400 Received: by mail-wr1-f65.google.com with SMTP id l17so2228077wrm.10 for ; Fri, 24 May 2019 09:27:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=o9AkQkRTyfMF48RGZO6XDYSB7I9U5iZYwHLrvW29JTc=; b=O+6Yr7OM7Pc0mZ+//HKVZHjBGXIZQvOYrswpEkp78/Q+As/E2rBJ/yv/xlzDC7H8x9 DSBeIaaMRELLs7uHFcK6WNM35tW6LXRKISTqfDkG0GZ5gQpZOUzKc+7kur0C9R4Sykpd pf6WwHNWCEgscnown4RhCD0943qChbet1hheO927MWTqym2A1FL8flF4xbQ9aMeBMygx inWUknPcmxNSf00bJfvFUR73EgfBv/u/QhHNCahdG01VvkMjtZXWOEXPtSoMrDfFFHFC 3fXqt1W2ofEvNk65F3zqNBjqmXd8kzddPuQwezhwPKHAxSfcFzIJIPrdAQvRahP+0vU+ VSMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=o9AkQkRTyfMF48RGZO6XDYSB7I9U5iZYwHLrvW29JTc=; b=XpAz0d2VtldR+qUTxlQPzSYDjbOHN9FHODQ1KxvvVkAIlSv9/OwLbmQSD6LA0lYJ/n p7zB2/k2ZI0V2sGok8GfEwisIPUVw8uKumZ1RSGkbuCcm74CjfghCsQzlENybAnPSpKQ jxH2eOvyox+7OFLx3JRLUBU//pEeflkdpygEdn04nKpBdZkcRxO2Q/+aVmgi69TRiuAn lzsFBuHU+8ia1YzXVvCOz5h5raiTI0SawDYuieSxDa2StSgshm3smgfyuUu+JqCQEk+Q WTrytpiO5cR3R7rrBfhuHuXIXVTNUylQfJXNioOnG7J0OQM/PmJhp84TsUbKiM6x4hRe 66jg== X-Gm-Message-State: APjAAAXymfCeENhtXsGvVO0oqXZgz5wFj93TaWerSt+EldgSWlWEMXJN 8uZk7FnMm3dfihHa1IMIvk2G4Q== X-Received: by 2002:a5d:4692:: with SMTP id u18mr52536614wrq.285.1558715260788; Fri, 24 May 2019 09:27:40 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:2042:d8f2:ded8:fa95]) by smtp.gmail.com with ESMTPSA id l6sm2200320wmi.24.2019.05.24.09.27.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 May 2019 09:27:40 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Ard Biesheuvel , Herbert Xu , Tudor Ambarus , Linus Walleij , Mika Westerberg Subject: [PATCH v2 3/6] crypto: atmel-ecc: factor out code that can be shared Date: Fri, 24 May 2019 18:26:48 +0200 Message-Id: <20190524162651.28189-4-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190524162651.28189-1-ard.biesheuvel@linaro.org> References: <20190524162651.28189-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org In preparation of adding support for the random number generator in Atmel atsha204a devices, refactor the existing atmel-ecc driver (which drives hardware that is closely related) so we can share the basic I2C and command queuing routines. Reviewed-by: Linus Walleij Signed-off-by: Ard Biesheuvel --- drivers/crypto/Kconfig | 4 + drivers/crypto/Makefile | 1 + drivers/crypto/atmel-ecc.c | 406 ++------------------ drivers/crypto/atmel-i2c.c | 349 +++++++++++++++++ drivers/crypto/{atmel-ecc.h => atmel-i2c.h} | 80 +++- 5 files changed, 451 insertions(+), 389 deletions(-) -- 2.20.1 diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 97ec8107eeef..ca7a5564e9ce 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -520,9 +520,13 @@ config CRYPTO_DEV_ATMEL_SHA To compile this driver as a module, choose M here: the module will be called atmel-sha. +config CRYPTO_DEV_ATMEL_I2C + tristate + config CRYPTO_DEV_ATMEL_ECC tristate "Support for Microchip / Atmel ECC hw accelerator" depends on I2C + select CRYPTO_DEV_ATMEL_I2C select CRYPTO_ECDH select CRC16 help diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index a23a7197fcd7..394e84089924 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o +obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/ obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 5705348f540f..ff02cc05affb 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -6,8 +6,6 @@ * Author: Tudor Ambarus */ -#include -#include #include #include #include @@ -23,41 +21,10 @@ #include #include #include -#include "atmel-ecc.h" - -/* Used for binding tfm objects to i2c clients. */ -struct atmel_ecc_driver_data { - struct list_head i2c_client_list; - spinlock_t i2c_list_lock; -} ____cacheline_aligned; +#include "atmel-i2c.h" static struct atmel_ecc_driver_data driver_data; -/** - * atmel_ecc_i2c_client_priv - i2c_client private data - * @client : pointer to i2c client device - * @i2c_client_list_node: part of i2c_client_list - * @lock : lock for sending i2c commands - * @wake_token : wake token array of zeros - * @wake_token_sz : size in bytes of the wake_token - * @tfm_count : number of active crypto transformations on i2c client - * - * Reads and writes from/to the i2c client are sequential. The first byte - * transmitted to the device is treated as the byte size. Any attempt to send - * more than this number of bytes will cause the device to not ACK those bytes. - * After the host writes a single command byte to the input buffer, reads are - * prohibited until after the device completes command execution. Use a mutex - * when sending i2c commands. - */ -struct atmel_ecc_i2c_client_priv { - struct i2c_client *client; - struct list_head i2c_client_list_node; - struct mutex lock; - u8 wake_token[WAKE_TOKEN_MAX_SIZE]; - size_t wake_token_sz; - atomic_t tfm_count ____cacheline_aligned; -}; - /** * atmel_ecdh_ctx - transformation context * @client : pointer to i2c client device @@ -80,188 +47,12 @@ struct atmel_ecdh_ctx { bool do_fallback; }; -/** - * atmel_ecc_work_data - data structure representing the work - * @ctx : transformation context. - * @cbk : pointer to a callback function to be invoked upon completion of this - * request. This has the form: - * callback(struct atmel_ecc_work_data *work_data, void *areq, u8 status) - * where: - * @work_data: data structure representing the work - * @areq : optional pointer to an argument passed with the original - * request. - * @status : status returned from the i2c client device or i2c error. - * @areq: optional pointer to a user argument for use at callback time. - * @work: describes the task to be executed. - * @cmd : structure used for communicating with the device. - */ -struct atmel_ecc_work_data { - struct atmel_ecdh_ctx *ctx; - void (*cbk)(struct atmel_ecc_work_data *work_data, void *areq, - int status); - void *areq; - struct work_struct work; - struct atmel_ecc_cmd cmd; -}; - -static u16 atmel_ecc_crc16(u16 crc, const u8 *buffer, size_t len) -{ - return cpu_to_le16(bitrev16(crc16(crc, buffer, len))); -} - -/** - * atmel_ecc_checksum() - Generate 16-bit CRC as required by ATMEL ECC. - * CRC16 verification of the count, opcode, param1, param2 and data bytes. - * The checksum is saved in little-endian format in the least significant - * two bytes of the command. CRC polynomial is 0x8005 and the initial register - * value should be zero. - * - * @cmd : structure used for communicating with the device. - */ -static void atmel_ecc_checksum(struct atmel_ecc_cmd *cmd) -{ - u8 *data = &cmd->count; - size_t len = cmd->count - CRC_SIZE; - u16 *crc16 = (u16 *)(data + len); - - *crc16 = atmel_ecc_crc16(0, data, len); -} - -static void atmel_ecc_init_read_cmd(struct atmel_ecc_cmd *cmd) -{ - cmd->word_addr = COMMAND; - cmd->opcode = OPCODE_READ; - /* - * Read the word from Configuration zone that contains the lock bytes - * (UserExtra, Selector, LockValue, LockConfig). - */ - cmd->param1 = CONFIG_ZONE; - cmd->param2 = DEVICE_LOCK_ADDR; - cmd->count = READ_COUNT; - - atmel_ecc_checksum(cmd); - - cmd->msecs = MAX_EXEC_TIME_READ; - cmd->rxsize = READ_RSP_SIZE; -} - -static void atmel_ecc_init_genkey_cmd(struct atmel_ecc_cmd *cmd, u16 keyid) -{ - cmd->word_addr = COMMAND; - cmd->count = GENKEY_COUNT; - cmd->opcode = OPCODE_GENKEY; - cmd->param1 = GENKEY_MODE_PRIVATE; - /* a random private key will be generated and stored in slot keyID */ - cmd->param2 = cpu_to_le16(keyid); - - atmel_ecc_checksum(cmd); - - cmd->msecs = MAX_EXEC_TIME_GENKEY; - cmd->rxsize = GENKEY_RSP_SIZE; -} - -static int atmel_ecc_init_ecdh_cmd(struct atmel_ecc_cmd *cmd, - struct scatterlist *pubkey) -{ - size_t copied; - - cmd->word_addr = COMMAND; - cmd->count = ECDH_COUNT; - cmd->opcode = OPCODE_ECDH; - cmd->param1 = ECDH_PREFIX_MODE; - /* private key slot */ - cmd->param2 = cpu_to_le16(DATA_SLOT_2); - - /* - * The device only supports NIST P256 ECC keys. The public key size will - * always be the same. Use a macro for the key size to avoid unnecessary - * computations. - */ - copied = sg_copy_to_buffer(pubkey, - sg_nents_for_len(pubkey, - ATMEL_ECC_PUBKEY_SIZE), - cmd->data, ATMEL_ECC_PUBKEY_SIZE); - if (copied != ATMEL_ECC_PUBKEY_SIZE) - return -EINVAL; - - atmel_ecc_checksum(cmd); - - cmd->msecs = MAX_EXEC_TIME_ECDH; - cmd->rxsize = ECDH_RSP_SIZE; - - return 0; -} - -/* - * After wake and after execution of a command, there will be error, status, or - * result bytes in the device's output register that can be retrieved by the - * system. When the length of that group is four bytes, the codes returned are - * detailed in error_list. - */ -static int atmel_ecc_status(struct device *dev, u8 *status) -{ - size_t err_list_len = ARRAY_SIZE(error_list); - int i; - u8 err_id = status[1]; - - if (*status != STATUS_SIZE) - return 0; - - if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) - return 0; - - for (i = 0; i < err_list_len; i++) - if (error_list[i].value == err_id) - break; - - /* if err_id is not in the error_list then ignore it */ - if (i != err_list_len) { - dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); - return err_id; - } - - return 0; -} - -static int atmel_ecc_wakeup(struct i2c_client *client) -{ - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); - u8 status[STATUS_RSP_SIZE]; - int ret; - - /* - * The device ignores any levels or transitions on the SCL pin when the - * device is idle, asleep or during waking up. Don't check for error - * when waking up the device. - */ - i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz); - - /* - * Wait to wake the device. Typical execution times for ecdh and genkey - * are around tens of milliseconds. Delta is chosen to 50 microseconds. - */ - usleep_range(TWHI_MIN, TWHI_MAX); - - ret = i2c_master_recv(client, status, STATUS_SIZE); - if (ret < 0) - return ret; - - return atmel_ecc_status(&client->dev, status); -} - -static int atmel_ecc_sleep(struct i2c_client *client) -{ - u8 sleep = SLEEP_TOKEN; - - return i2c_master_send(client, &sleep, 1); -} - -static void atmel_ecdh_done(struct atmel_ecc_work_data *work_data, void *areq, +static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, int status) { struct kpp_request *req = areq; struct atmel_ecdh_ctx *ctx = work_data->ctx; - struct atmel_ecc_cmd *cmd = &work_data->cmd; + struct atmel_i2c_cmd *cmd = &work_data->cmd; size_t copied, n_sz; if (status) @@ -282,82 +73,6 @@ static void atmel_ecdh_done(struct atmel_ecc_work_data *work_data, void *areq, kpp_request_complete(req, status); } -/* - * atmel_ecc_send_receive() - send a command to the device and receive its - * response. - * @client: i2c client device - * @cmd : structure used to communicate with the device - * - * After the device receives a Wake token, a watchdog counter starts within the - * device. After the watchdog timer expires, the device enters sleep mode - * regardless of whether some I/O transmission or command execution is in - * progress. If a command is attempted when insufficient time remains prior to - * watchdog timer execution, the device will return the watchdog timeout error - * code without attempting to execute the command. There is no way to reset the - * counter other than to put the device into sleep or idle mode and then - * wake it up again. - */ -static int atmel_ecc_send_receive(struct i2c_client *client, - struct atmel_ecc_cmd *cmd) -{ - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); - int ret; - - mutex_lock(&i2c_priv->lock); - - ret = atmel_ecc_wakeup(client); - if (ret) - goto err; - - /* send the command */ - ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); - if (ret < 0) - goto err; - - /* delay the appropriate amount of time for command to execute */ - msleep(cmd->msecs); - - /* receive the response */ - ret = i2c_master_recv(client, cmd->data, cmd->rxsize); - if (ret < 0) - goto err; - - /* put the device into low-power mode */ - ret = atmel_ecc_sleep(client); - if (ret < 0) - goto err; - - mutex_unlock(&i2c_priv->lock); - return atmel_ecc_status(&client->dev, cmd->data); -err: - mutex_unlock(&i2c_priv->lock); - return ret; -} - -static void atmel_ecc_work_handler(struct work_struct *work) -{ - struct atmel_ecc_work_data *work_data = - container_of(work, struct atmel_ecc_work_data, work); - struct atmel_ecc_cmd *cmd = &work_data->cmd; - struct i2c_client *client = work_data->ctx->client; - int status; - - status = atmel_ecc_send_receive(client, cmd); - work_data->cbk(work_data, work_data->areq, status); -} - -static void atmel_ecc_enqueue(struct atmel_ecc_work_data *work_data, - void (*cbk)(struct atmel_ecc_work_data *work_data, - void *areq, int status), - void *areq) -{ - work_data->cbk = (void *)cbk; - work_data->areq = areq; - - INIT_WORK(&work_data->work, atmel_ecc_work_handler); - schedule_work(&work_data->work); -} - static unsigned int atmel_ecdh_supported_curve(unsigned int curve_id) { if (curve_id == ECC_CURVE_NIST_P256) @@ -374,7 +89,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, unsigned int len) { struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); - struct atmel_ecc_cmd *cmd; + struct atmel_i2c_cmd *cmd; void *public_key; struct ecdh params; int ret = -ENOMEM; @@ -412,9 +127,9 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, ctx->do_fallback = false; ctx->curve_id = params.curve_id; - atmel_ecc_init_genkey_cmd(cmd, DATA_SLOT_2); + atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2); - ret = atmel_ecc_send_receive(ctx->client, cmd); + ret = atmel_i2c_send_receive(ctx->client, cmd); if (ret) goto free_public_key; @@ -444,6 +159,9 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req) return crypto_kpp_generate_public_key(req); } + if (!ctx->public_key) + return -EINVAL; + /* might want less than we've got */ nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len); @@ -461,7 +179,7 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); - struct atmel_ecc_work_data *work_data; + struct atmel_i2c_work_data *work_data; gfp_t gfp; int ret; @@ -482,12 +200,13 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) return -ENOMEM; work_data->ctx = ctx; + work_data->client = ctx->client; - ret = atmel_ecc_init_ecdh_cmd(&work_data->cmd, req->src); + ret = atmel_i2c_init_ecdh_cmd(&work_data->cmd, req->src); if (ret) goto free_work_data; - atmel_ecc_enqueue(work_data, atmel_ecdh_done, req); + atmel_i2c_enqueue(work_data, atmel_ecdh_done, req); return -EINPROGRESS; @@ -498,7 +217,7 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) static struct i2c_client *atmel_ecc_i2c_client_alloc(void) { - struct atmel_ecc_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; + struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; struct i2c_client *client = ERR_PTR(-ENODEV); int min_tfm_cnt = INT_MAX; int tfm_cnt; @@ -533,7 +252,7 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void) static void atmel_ecc_i2c_client_free(struct i2c_client *client) { - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); atomic_dec(&i2c_priv->tfm_count); } @@ -604,99 +323,18 @@ static struct kpp_alg atmel_ecdh = { }, }; -static inline size_t atmel_ecc_wake_token_sz(u32 bus_clk_rate) -{ - u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC); - - /* return the size of the wake_token in bytes */ - return DIV_ROUND_UP(no_of_bits, 8); -} - -static int device_sanity_check(struct i2c_client *client) -{ - struct atmel_ecc_cmd *cmd; - int ret; - - cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - atmel_ecc_init_read_cmd(cmd); - - ret = atmel_ecc_send_receive(client, cmd); - if (ret) - goto free_cmd; - - /* - * It is vital that the Configuration, Data and OTP zones be locked - * prior to release into the field of the system containing the device. - * Failure to lock these zones may permit modification of any secret - * keys and may lead to other security problems. - */ - if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) { - dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n"); - ret = -ENOTSUPP; - } - - /* fall through */ -free_cmd: - kfree(cmd); - return ret; -} - static int atmel_ecc_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct atmel_ecc_i2c_client_priv *i2c_priv; - struct device *dev = &client->dev; + struct atmel_i2c_client_priv *i2c_priv; int ret; - u32 bus_clk_rate; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(dev, "I2C_FUNC_I2C not supported\n"); - return -ENODEV; - } - - clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); - if (!clk_rate) { - ret = device_property_read_u32(&client->adapter->dev, - "clock-frequency", &bus_clk_rate); - if (ret) { - dev_err(dev, "failed to read clock-frequency property\n"); - return ret; - } - } - - if (bus_clk_rate > 1000000L) { - dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", - bus_clk_rate); - return -EINVAL; - } - - i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); - if (!i2c_priv) - return -ENOMEM; - - i2c_priv->client = client; - mutex_init(&i2c_priv->lock); - - /* - * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - - * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz - * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE. - */ - i2c_priv->wake_token_sz = atmel_ecc_wake_token_sz(bus_clk_rate); - - memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token)); - - atomic_set(&i2c_priv->tfm_count, 0); - - i2c_set_clientdata(client, i2c_priv); - - ret = device_sanity_check(client); + ret = atmel_i2c_probe(client, id); if (ret) return ret; + i2c_priv = i2c_get_clientdata(client); + spin_lock(&driver_data.i2c_list_lock); list_add_tail(&i2c_priv->i2c_client_list_node, &driver_data.i2c_client_list); @@ -708,10 +346,10 @@ static int atmel_ecc_probe(struct i2c_client *client, list_del(&i2c_priv->i2c_client_list_node); spin_unlock(&driver_data.i2c_list_lock); - dev_err(dev, "%s alg registration failed\n", + dev_err(&client->dev, "%s alg registration failed\n", atmel_ecdh.base.cra_driver_name); } else { - dev_info(dev, "atmel ecc algorithms registered in /proc/crypto\n"); + dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n"); } return ret; @@ -719,7 +357,7 @@ static int atmel_ecc_probe(struct i2c_client *client, static int atmel_ecc_remove(struct i2c_client *client) { - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); /* Return EBUSY if i2c client already allocated. */ if (atomic_read(&i2c_priv->tfm_count)) { diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c new file mode 100644 index 000000000000..5e099368d120 --- /dev/null +++ b/drivers/crypto/atmel-i2c.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip / Atmel ECC (I2C) driver. + * + * Copyright (c) 2017, Microchip Technology Inc. + * Author: Tudor Ambarus + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "atmel-i2c.h" + +/** + * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC. + * CRC16 verification of the count, opcode, param1, param2 and data bytes. + * The checksum is saved in little-endian format in the least significant + * two bytes of the command. CRC polynomial is 0x8005 and the initial register + * value should be zero. + * + * @cmd : structure used for communicating with the device. + */ +static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd) +{ + u8 *data = &cmd->count; + size_t len = cmd->count - CRC_SIZE; + u16 *__crc16 = (u16 *)(data + len); + + *__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len))); +} + +void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd) +{ + cmd->word_addr = COMMAND; + cmd->opcode = OPCODE_READ; + /* + * Read the word from Configuration zone that contains the lock bytes + * (UserExtra, Selector, LockValue, LockConfig). + */ + cmd->param1 = CONFIG_ZONE; + cmd->param2 = DEVICE_LOCK_ADDR; + cmd->count = READ_COUNT; + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_READ; + cmd->rxsize = READ_RSP_SIZE; +} +EXPORT_SYMBOL(atmel_i2c_init_read_cmd); + +void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid) +{ + cmd->word_addr = COMMAND; + cmd->count = GENKEY_COUNT; + cmd->opcode = OPCODE_GENKEY; + cmd->param1 = GENKEY_MODE_PRIVATE; + /* a random private key will be generated and stored in slot keyID */ + cmd->param2 = cpu_to_le16(keyid); + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_GENKEY; + cmd->rxsize = GENKEY_RSP_SIZE; +} +EXPORT_SYMBOL(atmel_i2c_init_genkey_cmd); + +int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, + struct scatterlist *pubkey) +{ + size_t copied; + + cmd->word_addr = COMMAND; + cmd->count = ECDH_COUNT; + cmd->opcode = OPCODE_ECDH; + cmd->param1 = ECDH_PREFIX_MODE; + /* private key slot */ + cmd->param2 = cpu_to_le16(DATA_SLOT_2); + + /* + * The device only supports NIST P256 ECC keys. The public key size will + * always be the same. Use a macro for the key size to avoid unnecessary + * computations. + */ + copied = sg_copy_to_buffer(pubkey, + sg_nents_for_len(pubkey, + ATMEL_ECC_PUBKEY_SIZE), + cmd->data, ATMEL_ECC_PUBKEY_SIZE); + if (copied != ATMEL_ECC_PUBKEY_SIZE) + return -EINVAL; + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_ECDH; + cmd->rxsize = ECDH_RSP_SIZE; + + return 0; +} +EXPORT_SYMBOL(atmel_i2c_init_ecdh_cmd); + +/* + * After wake and after execution of a command, there will be error, status, or + * result bytes in the device's output register that can be retrieved by the + * system. When the length of that group is four bytes, the codes returned are + * detailed in error_list. + */ +static int atmel_i2c_status(struct device *dev, u8 *status) +{ + size_t err_list_len = ARRAY_SIZE(error_list); + int i; + u8 err_id = status[1]; + + if (*status != STATUS_SIZE) + return 0; + + if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) + return 0; + + for (i = 0; i < err_list_len; i++) + if (error_list[i].value == err_id) + break; + + /* if err_id is not in the error_list then ignore it */ + if (i != err_list_len) { + dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); + return err_id; + } + + return 0; +} + +static int atmel_i2c_wakeup(struct i2c_client *client) +{ + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + u8 status[STATUS_RSP_SIZE]; + int ret; + + /* + * The device ignores any levels or transitions on the SCL pin when the + * device is idle, asleep or during waking up. Don't check for error + * when waking up the device. + */ + i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz); + + /* + * Wait to wake the device. Typical execution times for ecdh and genkey + * are around tens of milliseconds. Delta is chosen to 50 microseconds. + */ + usleep_range(TWHI_MIN, TWHI_MAX); + + ret = i2c_master_recv(client, status, STATUS_SIZE); + if (ret < 0) + return ret; + + return atmel_i2c_status(&client->dev, status); +} + +static int atmel_i2c_sleep(struct i2c_client *client) +{ + u8 sleep = SLEEP_TOKEN; + + return i2c_master_send(client, &sleep, 1); +} + +/* + * atmel_i2c_send_receive() - send a command to the device and receive its + * response. + * @client: i2c client device + * @cmd : structure used to communicate with the device + * + * After the device receives a Wake token, a watchdog counter starts within the + * device. After the watchdog timer expires, the device enters sleep mode + * regardless of whether some I/O transmission or command execution is in + * progress. If a command is attempted when insufficient time remains prior to + * watchdog timer execution, the device will return the watchdog timeout error + * code without attempting to execute the command. There is no way to reset the + * counter other than to put the device into sleep or idle mode and then + * wake it up again. + */ +int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd) +{ + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + int ret; + + mutex_lock(&i2c_priv->lock); + + ret = atmel_i2c_wakeup(client); + if (ret) + goto err; + + /* send the command */ + ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); + if (ret < 0) + goto err; + + /* delay the appropriate amount of time for command to execute */ + msleep(cmd->msecs); + + /* receive the response */ + ret = i2c_master_recv(client, cmd->data, cmd->rxsize); + if (ret < 0) + goto err; + + /* put the device into low-power mode */ + ret = atmel_i2c_sleep(client); + if (ret < 0) + goto err; + + mutex_unlock(&i2c_priv->lock); + return atmel_i2c_status(&client->dev, cmd->data); +err: + mutex_unlock(&i2c_priv->lock); + return ret; +} +EXPORT_SYMBOL(atmel_i2c_send_receive); + +static void atmel_i2c_work_handler(struct work_struct *work) +{ + struct atmel_i2c_work_data *work_data = + container_of(work, struct atmel_i2c_work_data, work); + struct atmel_i2c_cmd *cmd = &work_data->cmd; + struct i2c_client *client = work_data->client; + int status; + + status = atmel_i2c_send_receive(client, cmd); + work_data->cbk(work_data, work_data->areq, status); +} + +void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, + void (*cbk)(struct atmel_i2c_work_data *work_data, + void *areq, int status), + void *areq) +{ + work_data->cbk = (void *)cbk; + work_data->areq = areq; + + INIT_WORK(&work_data->work, atmel_i2c_work_handler); + schedule_work(&work_data->work); +} +EXPORT_SYMBOL(atmel_i2c_enqueue); + +static inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate) +{ + u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC); + + /* return the size of the wake_token in bytes */ + return DIV_ROUND_UP(no_of_bits, 8); +} + +static int device_sanity_check(struct i2c_client *client) +{ + struct atmel_i2c_cmd *cmd; + int ret; + + cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + atmel_i2c_init_read_cmd(cmd); + + ret = atmel_i2c_send_receive(client, cmd); + if (ret) + goto free_cmd; + + /* + * It is vital that the Configuration, Data and OTP zones be locked + * prior to release into the field of the system containing the device. + * Failure to lock these zones may permit modification of any secret + * keys and may lead to other security problems. + */ + if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) { + dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n"); + ret = -ENOTSUPP; + } + + /* fall through */ +free_cmd: + kfree(cmd); + return ret; +} + +int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct atmel_i2c_client_priv *i2c_priv; + struct device *dev = &client->dev; + int ret; + u32 bus_clk_rate; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "I2C_FUNC_I2C not supported\n"); + return -ENODEV; + } + + bus_clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); + if (!bus_clk_rate) { + ret = device_property_read_u32(&client->adapter->dev, + "clock-frequency", &bus_clk_rate); + if (ret) { + dev_err(dev, "failed to read clock-frequency property\n"); + return ret; + } + } + + if (bus_clk_rate > 1000000L) { + dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", + bus_clk_rate); + return -EINVAL; + } + + i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); + if (!i2c_priv) + return -ENOMEM; + + i2c_priv->client = client; + mutex_init(&i2c_priv->lock); + + /* + * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - + * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz + * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE. + */ + i2c_priv->wake_token_sz = atmel_i2c_wake_token_sz(bus_clk_rate); + + memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token)); + + atomic_set(&i2c_priv->tfm_count, 0); + + i2c_set_clientdata(client, i2c_priv); + + ret = device_sanity_check(client); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(atmel_i2c_probe); + +MODULE_AUTHOR("Tudor Ambarus "); +MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/crypto/atmel-ecc.h b/drivers/crypto/atmel-i2c.h similarity index 51% rename from drivers/crypto/atmel-ecc.h rename to drivers/crypto/atmel-i2c.h index 643a3b947338..82de5166acfa 100644 --- a/drivers/crypto/atmel-ecc.h +++ b/drivers/crypto/atmel-i2c.h @@ -4,8 +4,8 @@ * Author: Tudor Ambarus */ -#ifndef __ATMEL_ECC_H__ -#define __ATMEL_ECC_H__ +#ifndef __ATMEL_I2C_H__ +#define __ATMEL_I2C_H__ #define ATMEL_ECC_PRIORITY 300 @@ -31,7 +31,7 @@ #define MAX_RSP_SIZE GENKEY_RSP_SIZE /** - * atmel_ecc_cmd - structure used for communicating with the device. + * atmel_i2c_cmd - structure used for communicating with the device. * @word_addr: indicates the function of the packet sent to the device. This * byte should have a value of COMMAND for normal operation. * @count : number of bytes to be transferred to (or from) the device. @@ -42,7 +42,7 @@ * @rxsize : size of the data received from i2c client. * @msecs : command execution time in milliseconds */ -struct atmel_ecc_cmd { +struct atmel_i2c_cmd { u8 word_addr; u8 count; u8 opcode; @@ -113,4 +113,74 @@ static const struct { #define ECDH_COUNT 71 #define ECDH_PREFIX_MODE 0x00 -#endif /* __ATMEL_ECC_H__ */ +/* Used for binding tfm objects to i2c clients. */ +struct atmel_ecc_driver_data { + struct list_head i2c_client_list; + spinlock_t i2c_list_lock; +} ____cacheline_aligned; + +/** + * atmel_i2c_client_priv - i2c_client private data + * @client : pointer to i2c client device + * @i2c_client_list_node: part of i2c_client_list + * @lock : lock for sending i2c commands + * @wake_token : wake token array of zeros + * @wake_token_sz : size in bytes of the wake_token + * @tfm_count : number of active crypto transformations on i2c client + * + * Reads and writes from/to the i2c client are sequential. The first byte + * transmitted to the device is treated as the byte size. Any attempt to send + * more than this number of bytes will cause the device to not ACK those bytes. + * After the host writes a single command byte to the input buffer, reads are + * prohibited until after the device completes command execution. Use a mutex + * when sending i2c commands. + */ +struct atmel_i2c_client_priv { + struct i2c_client *client; + struct list_head i2c_client_list_node; + struct mutex lock; + u8 wake_token[WAKE_TOKEN_MAX_SIZE]; + size_t wake_token_sz; + atomic_t tfm_count ____cacheline_aligned; +}; + +/** + * atmel_i2c_work_data - data structure representing the work + * @ctx : transformation context. + * @cbk : pointer to a callback function to be invoked upon completion of this + * request. This has the form: + * callback(struct atmel_i2c_work_data *work_data, void *areq, u8 status) + * where: + * @work_data: data structure representing the work + * @areq : optional pointer to an argument passed with the original + * request. + * @status : status returned from the i2c client device or i2c error. + * @areq: optional pointer to a user argument for use at callback time. + * @work: describes the task to be executed. + * @cmd : structure used for communicating with the device. + */ +struct atmel_i2c_work_data { + void *ctx; + struct i2c_client *client; + void (*cbk)(struct atmel_i2c_work_data *work_data, void *areq, + int status); + void *areq; + struct work_struct work; + struct atmel_i2c_cmd cmd; +}; + +int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); + +void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, + void (*cbk)(struct atmel_i2c_work_data *work_data, + void *areq, int status), + void *areq); + +int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd); + +void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd); +void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid); +int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, + struct scatterlist *pubkey); + +#endif /* __ATMEL_I2C_H__ */ From patchwork Fri May 24 16:26:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 165140 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp3814281ili; Fri, 24 May 2019 09:27:45 -0700 (PDT) X-Google-Smtp-Source: APXvYqyO2x2lwuBEHalLp4vi3CcokhBfojqR21ILMB0Fg6t1+IQ5qdvU/mg5R2mKw5WBwqw2B3XR X-Received: by 2002:a65:530d:: with SMTP id m13mr11728140pgq.68.1558715265687; Fri, 24 May 2019 09:27:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558715265; cv=none; d=google.com; s=arc-20160816; b=vKzaqjUL8OPBkc83a96us690LI8QH75ET9Z/yvCVM+s0BL7efntYW81aXSmlE+3Pcg fTXuZbcH/TVXUDbHbo/3XT/7VG2C17omKiH/1//v2XEmrH0HmZzjODqXzRX73lRuLhmN LbHAe5QPvKHaI8GPoHw/aYtlV7d2a3n3/Ea7Q6aogF/3e2FvYKNfy/pouf36YLeOapZR ZaE48OsV5uy38aUgTqCcYTDZbw43hy/hV7a8z+I5G1f0cZPyp8iEU/kjgCQLbe7cMD3y mvKTUWED6BKvG0eBA+jV6K1CkbPvqrT9dEzzfI7rlaViFISzAZYt8pZ1amO4r9Mid2ZA scTA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=fEjtPdaBAqYRZI8UVsqNWtXwmYQF0pkPjODsBVdhtdo=; b=vlDc03d1QoU3mnCdeNLq2B+cEfokA6pUlo6a7intGBGDwdmzPEfhO7hAQ27eTtZQ0f L0BtUuEUPeAYxm+xWANf07FpgAW5X2JY//MtiGHeepfqTEklmSQ2aKOYW+EEyOkLPkwp vOlY/sBFPsq+Np7cLFqgM9jHyR4LtBFjzH5B3zXdl9Hb5w9Vln47TQ7uFccG1Fa4v7BJ 6RbHDFvw0ZHUBxqx2mfrDxHrqBHo1YBW3HfE5nV/5znYqRRGS5NgbyKYsRkK0CYPeQge eJKbOnFb7dS/6OEGjAa//10D1FEU22Qexy4A/y5JGz5RkFcNnQcndKET8tWUWmUP+GjG QX7A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=EAEiG0Sl; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r69si4906966pgr.120.2019.05.24.09.27.45; Fri, 24 May 2019 09:27:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=EAEiG0Sl; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390623AbfEXQ1o (ORCPT + 7 others); Fri, 24 May 2019 12:27:44 -0400 Received: from mail-wr1-f68.google.com ([209.85.221.68]:39770 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390662AbfEXQ1o (ORCPT ); Fri, 24 May 2019 12:27:44 -0400 Received: by mail-wr1-f68.google.com with SMTP id e2so1861543wrv.6 for ; Fri, 24 May 2019 09:27:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=fEjtPdaBAqYRZI8UVsqNWtXwmYQF0pkPjODsBVdhtdo=; b=EAEiG0Slgf2dbGN1ZsAmwlM5Tw6BOTdlwNxgjGUJjZGjGBni+Sdfph0avf/Abgm9mT n5wtJEO5hw2Myhpzx6upQtWmbH0ERyZh548xHOu+Px9Dtlf8JfMBxR9ttiteYr3rbsZM zZ+lGgHGfvzQOt1nFnBYNhts8lWC3rwwbZb0l1dXNiZt3lt8sGXy463gfoFkQUQmtIjY cFKNC9uNUbeTRlM5fSu75uhD0Q1JzKWdV7gjXLbkdzHO5FEkX13F3RN5oqK3x7vgHakT EPpweoBzV0y/C0Hp4i/mno1z7lac7yQqZEfvU3EMzAMmFOqpEvzh/FDbJ7oNXjp2ezzO xBwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fEjtPdaBAqYRZI8UVsqNWtXwmYQF0pkPjODsBVdhtdo=; b=mO951NUZ/GnxcsfkTP9nLeVkjyPWl706P1E+4BfIaxsHEuGxa5pZMg7DST89i7nmcd PBTcmJwo96JiOOTl+sCahcqAaRPlvsG91th2KSfEpCx8BULGjsEWeyaHqdkI1aHDeSMy pJ61Y2KRxnjfS8GkP830/hdlKFLZ6Y1a/chzi/B22wPrAyu6M2Kw+H9Xu713I+JanNYL 2ZsfCLVDZ35dPMz9QkWlG9HgEUd+BezNd/pDPhqXftjOaNhVKceIqmEoW353jFAu/hE2 4Trm/NZhGeQhxOX5J7DNHwZmBJod7g2tu0XHcpIPIR3yLpE20oe3IhOqQEWuQZ9sRp+O LeqA== X-Gm-Message-State: APjAAAXgO7gdzko+oIXb6ClkgN000zsgl/oyDlc6pGlsdSabHFKewSuF DmW5CLLjVFoLcGN6gpKik07e9A== X-Received: by 2002:a5d:68d2:: with SMTP id p18mr59634313wrw.56.1558715262003; Fri, 24 May 2019 09:27:42 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:2042:d8f2:ded8:fa95]) by smtp.gmail.com with ESMTPSA id l6sm2200320wmi.24.2019.05.24.09.27.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 May 2019 09:27:41 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Ard Biesheuvel , Herbert Xu , Tudor Ambarus , Linus Walleij , Mika Westerberg Subject: [PATCH v2 4/6] crypto: atmel-i2c: add support for SHA204A random number generator Date: Fri, 24 May 2019 18:26:49 +0200 Message-Id: <20190524162651.28189-5-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190524162651.28189-1-ard.biesheuvel@linaro.org> References: <20190524162651.28189-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The Linaro/96boards Secure96 mezzanine contains (among other things) an Atmel SHA204A symmetric crypto processor. This chip implements a number of different functionalities, but one that is highly useful for many different 96boards platforms is the random number generator. So let's implement a driver for the SHA204A, and for the time being, implement support for the random number generator only. Reviewed-by: Linus Walleij Signed-off-by: Ard Biesheuvel --- drivers/crypto/Kconfig | 14 ++ drivers/crypto/Makefile | 1 + drivers/crypto/atmel-i2c.c | 15 ++ drivers/crypto/atmel-i2c.h | 10 ++ drivers/crypto/atmel-sha204a.c | 171 ++++++++++++++++++++ 5 files changed, 211 insertions(+) -- 2.20.1 diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index ca7a5564e9ce..fe01a9905ab1 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -537,6 +537,20 @@ config CRYPTO_DEV_ATMEL_ECC To compile this driver as a module, choose M here: the module will be called atmel-ecc. +config CRYPTO_DEV_ATMEL_SHA204A + tristate "Support for Microchip / Atmel SHA accelerator and RNG" + depends on I2C + select CRYPTO_DEV_ATMEL_I2C + select HW_RANDOM + help + Microhip / Atmel SHA accelerator and RNG. + Select this if you want to use the Microchip / Atmel SHA204A + module as a random number generator. (Other functions of the + chip are currently not exposed by this driver) + + To compile this driver as a module, choose M here: the module + will be called atmel-sha204a. + config CRYPTO_DEV_CCP bool "Support for AMD Secure Processor" depends on ((X86 && PCI) || (ARM64 && (OF_ADDRESS || ACPI))) && HAS_IOMEM diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 394e84089924..afc4753b5d28 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o +obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA204A) += atmel-sha204a.o obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/ obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/ diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c index 5e099368d120..be49ab7f4338 100644 --- a/drivers/crypto/atmel-i2c.c +++ b/drivers/crypto/atmel-i2c.c @@ -58,6 +58,21 @@ void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd) } EXPORT_SYMBOL(atmel_i2c_init_read_cmd); +void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd) +{ + cmd->word_addr = COMMAND; + cmd->opcode = OPCODE_RANDOM; + cmd->param1 = 0; + cmd->param2 = 0; + cmd->count = RANDOM_COUNT; + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_RANDOM; + cmd->rxsize = RANDOM_RSP_SIZE; +} +EXPORT_SYMBOL(atmel_i2c_init_random_cmd); + void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid) { cmd->word_addr = COMMAND; diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h index 82de5166acfa..c6bd43b78f33 100644 --- a/drivers/crypto/atmel-i2c.h +++ b/drivers/crypto/atmel-i2c.h @@ -7,6 +7,8 @@ #ifndef __ATMEL_I2C_H__ #define __ATMEL_I2C_H__ +#include + #define ATMEL_ECC_PRIORITY 300 #define COMMAND 0x03 /* packet function */ @@ -28,6 +30,7 @@ #define GENKEY_RSP_SIZE (ATMEL_ECC_PUBKEY_SIZE + \ CMD_OVERHEAD_SIZE) #define READ_RSP_SIZE (4 + CMD_OVERHEAD_SIZE) +#define RANDOM_RSP_SIZE (32 + CMD_OVERHEAD_SIZE) #define MAX_RSP_SIZE GENKEY_RSP_SIZE /** @@ -96,15 +99,20 @@ static const struct { #define MAX_EXEC_TIME_ECDH 58 #define MAX_EXEC_TIME_GENKEY 115 #define MAX_EXEC_TIME_READ 1 +#define MAX_EXEC_TIME_RANDOM 50 /* Command opcode */ #define OPCODE_ECDH 0x43 #define OPCODE_GENKEY 0x40 #define OPCODE_READ 0x02 +#define OPCODE_RANDOM 0x1b /* Definitions for the READ Command */ #define READ_COUNT 7 +/* Definitions for the RANDOM Command */ +#define RANDOM_COUNT 7 + /* Definitions for the GenKey Command */ #define GENKEY_COUNT 7 #define GENKEY_MODE_PRIVATE 0x04 @@ -142,6 +150,7 @@ struct atmel_i2c_client_priv { u8 wake_token[WAKE_TOKEN_MAX_SIZE]; size_t wake_token_sz; atomic_t tfm_count ____cacheline_aligned; + struct hwrng hwrng; }; /** @@ -179,6 +188,7 @@ void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd); void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd); +void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd); void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid); int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, struct scatterlist *pubkey); diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c new file mode 100644 index 000000000000..ea0d2068ea4f --- /dev/null +++ b/drivers/crypto/atmel-sha204a.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip / Atmel SHA204A (I2C) driver. + * + * Copyright (c) 2019 Linaro, Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "atmel-i2c.h" + +static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data, + void *areq, int status) +{ + struct atmel_i2c_client_priv *i2c_priv = work_data->ctx; + struct hwrng *rng = areq; + + if (status) + dev_warn_ratelimited(&i2c_priv->client->dev, + "i2c transaction failed (%d)\n", + status); + + rng->priv = (unsigned long)work_data; + atomic_dec(&i2c_priv->tfm_count); +} + +static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data, + size_t max) +{ + struct atmel_i2c_client_priv *i2c_priv; + struct atmel_i2c_work_data *work_data; + + i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng); + + /* keep maximum 1 asynchronous read in flight at any time */ + if (!atomic_add_unless(&i2c_priv->tfm_count, 1, 1)) + return 0; + + if (rng->priv) { + work_data = (struct atmel_i2c_work_data *)rng->priv; + max = min(sizeof(work_data->cmd.data), max); + memcpy(data, &work_data->cmd.data, max); + rng->priv = 0; + } else { + work_data = kmalloc(sizeof(*work_data), GFP_ATOMIC); + if (!work_data) + return -ENOMEM; + + work_data->ctx = i2c_priv; + work_data->client = i2c_priv->client; + + max = 0; + } + + atmel_i2c_init_random_cmd(&work_data->cmd); + atmel_i2c_enqueue(work_data, atmel_sha204a_rng_done, rng); + + return max; +} + +static int atmel_sha204a_rng_read(struct hwrng *rng, void *data, size_t max, + bool wait) +{ + struct atmel_i2c_client_priv *i2c_priv; + struct atmel_i2c_cmd cmd; + int ret; + + if (!wait) + return atmel_sha204a_rng_read_nonblocking(rng, data, max); + + i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng); + + atmel_i2c_init_random_cmd(&cmd); + + ret = atmel_i2c_send_receive(i2c_priv->client, &cmd); + if (ret) + return ret; + + max = min(sizeof(cmd.data), max); + memcpy(data, cmd.data, max); + + return max; +} + +static int atmel_sha204a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct atmel_i2c_client_priv *i2c_priv; + int ret; + + ret = atmel_i2c_probe(client, id); + if (ret) + return ret; + + i2c_priv = i2c_get_clientdata(client); + + memset(&i2c_priv->hwrng, 0, sizeof(i2c_priv->hwrng)); + + i2c_priv->hwrng.name = dev_name(&client->dev); + i2c_priv->hwrng.read = atmel_sha204a_rng_read; + i2c_priv->hwrng.quality = 1024; + + ret = hwrng_register(&i2c_priv->hwrng); + if (ret) + dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); + + return ret; +} + +static int atmel_sha204a_remove(struct i2c_client *client) +{ + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + + if (atomic_read(&i2c_priv->tfm_count)) { + dev_err(&client->dev, "Device is busy\n"); + return -EBUSY; + } + + if (i2c_priv->hwrng.priv) + kfree((void *)i2c_priv->hwrng.priv); + hwrng_unregister(&i2c_priv->hwrng); + + return 0; +} + +static const struct of_device_id atmel_sha204a_dt_ids[] = { + { .compatible = "atmel,atsha204a", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); + +static const struct i2c_device_id atmel_sha204a_id[] = { + { "atsha204a", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id); + +static struct i2c_driver atmel_sha204a_driver = { + .probe = atmel_sha204a_probe, + .remove = atmel_sha204a_remove, + .id_table = atmel_sha204a_id, + + .driver.name = "atmel-sha204a", + .driver.of_match_table = of_match_ptr(atmel_sha204a_dt_ids), +}; + +static int __init atmel_sha204a_init(void) +{ + return i2c_add_driver(&atmel_sha204a_driver); +} + +static void __exit atmel_sha204a_exit(void) +{ + flush_scheduled_work(); + i2c_del_driver(&atmel_sha204a_driver); +} + +module_init(atmel_sha204a_init); +module_exit(atmel_sha204a_exit); + +MODULE_AUTHOR("Ard Biesheuvel "); +MODULE_LICENSE("GPL v2"); From patchwork Fri May 24 16:26:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 165141 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp3814290ili; Fri, 24 May 2019 09:27:46 -0700 (PDT) X-Google-Smtp-Source: APXvYqzft315nMcYqaFkmjvt5zMeXmOz9anvGWTiIhL+L1wqeFbFpVmLtcLq9zJ2lsBPm+swoynk X-Received: by 2002:a62:5653:: with SMTP id k80mr112862987pfb.144.1558715266140; Fri, 24 May 2019 09:27:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558715266; cv=none; d=google.com; s=arc-20160816; b=GCEBD9Q9Jj9Kl4jpqCuhm7KtZHKxFrK4X0Rm91Ap2Hrkdg3LvHv1lqwuEZVO8XQ/nI ua/DQRHr2/1la9T3EOAOyNIrw/L7t11aKRcARymITa59Bq+Ef+NXE6DpT0jrhrjBjWDJ 4xpm7N4z6B3FCr2V2wW9ttfaxhzfJaMHqyrtbtXceaNpZhUWMx5rK2s+uyS5N6TUkGD5 cUxgDcsVITUYSyN9AGXqO/VYxPgkihTcbX229xqMx+9zfq5kA0uxqMCKswtp1kCG3O0N FLMw5ZYuCHIoIm+olou54TnhWRuKYZjYxSYC61Na6ROt0krc1ZydOs8d5hDoj7xl8IGJ Va+Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=BDVCH2sHIJOl3oTxOH2Xw8NSMYpE4DumvzxW/scZEI8=; b=HFxVcnZxhU5DWgB5HwbXWetzIMHiZ73KX4F96t0DBiQ+N3f5Rr8FtNzcTDhUFaiBea JoKF83LobB94lC6oDJfZhS6FXdwSf1S4EKw4WLvOhZIn66dHtj5oj9BRjEXOCgM8SZqu +1QqCBmy70Y4yYh5Ht30T4noK41tA6am3WHtGI70wVOJlImdQhCARaL/U7/0Yvd0ZHNZ RnFGOB9Ikg1Ic6jeQBuJg4WcqoIijJoYRImHVZe/QyWlw6yTAnnI1ZkCG8xNHtnQAHK9 APG8XRhe9pUYdV/JhHA984VNihJL++o1q39XGEiREj82x0IFdaWGDWHB0PXjIonk4ikO luiw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=xkOIhFq0; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r69si4906966pgr.120.2019.05.24.09.27.45; Fri, 24 May 2019 09:27:46 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=xkOIhFq0; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390662AbfEXQ1p (ORCPT + 7 others); Fri, 24 May 2019 12:27:45 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:46198 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390702AbfEXQ1o (ORCPT ); Fri, 24 May 2019 12:27:44 -0400 Received: by mail-wr1-f65.google.com with SMTP id r7so10606853wrr.13 for ; Fri, 24 May 2019 09:27:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BDVCH2sHIJOl3oTxOH2Xw8NSMYpE4DumvzxW/scZEI8=; b=xkOIhFq0XHfmFE1n3FRXs6JDt2lQu5s66J2ADnAbAa6G2kZ+fdlzQ6RAtv2nlGhsyM R1rf+nYHj8/njLWYLvOIXVxdniD8av3d/k/Pg2GCmUlhTOEeVlsr2y1JaK/4roNGmv8Q NxZ/oitIzGsyzysXL7SpXZWRuERubYmKXWV1S3WM1WxnKiqVxVODCo70sO5Gu3QvaDSX vFUPndyRzLKABkHMXXtWLuPUTiMH2UM5PqOREsziEIhZtW6wx12xwFyl3imoHDy5EFqg gM3CC7Te/YcQRp+VUJvX3mr3oZKOCbJF94ooJFH83CtwHuTJM1vKWOGqAttr+T3YCxoK UvHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BDVCH2sHIJOl3oTxOH2Xw8NSMYpE4DumvzxW/scZEI8=; b=jG7OEvxDb1ezjUP+duWnwUsVJOritDwQnOGE2d96/PTQb96TBiy4oEejnNjiefkGku 15BwFk0735KNUdTrktJE3SjC8jRey74cUEhF2TKUtFzWHXCL4UbpYGbkaNvFjOZ6SfbC OW+z6MfbTIdRY4drZl0smfIF3LqysK3KK3BZac7OurWpbdStWFobwLfTeuyQ+A3lqSRQ Mgj270xuZ0rlf2KXTb4WZGe+cVnGZz4uDl0pC8J61QvHL/xSy1ROBoF+Tmj8FNP654d8 jFE1RENTRw7hXsZD0CEPli8T4M46Ge6kOHZL8FpFiiJuyiZyUiYoAZdVqrEyW0I151lE LGrA== X-Gm-Message-State: APjAAAUuD0rDhDp2oN50aiWQLydB9k5xh9WxMpjTjr5CqcQGIPhJHJ/n YCcIiSAMtgNBb3lBnCYU8v5gyg== X-Received: by 2002:a5d:61c4:: with SMTP id q4mr53273464wrv.295.1558715263199; Fri, 24 May 2019 09:27:43 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:2042:d8f2:ded8:fa95]) by smtp.gmail.com with ESMTPSA id l6sm2200320wmi.24.2019.05.24.09.27.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 May 2019 09:27:42 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Ard Biesheuvel , Herbert Xu , Tudor Ambarus , Linus Walleij , Mika Westerberg Subject: [PATCH v2 5/6] dt-bindings: add Atmel SHA204A I2C crypto processor Date: Fri, 24 May 2019 18:26:50 +0200 Message-Id: <20190524162651.28189-6-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190524162651.28189-1-ard.biesheuvel@linaro.org> References: <20190524162651.28189-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add a compatible string for the Atmel SHA204A I2C crypto processor. Signed-off-by: Ard Biesheuvel --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) -- 2.20.1 Reviewed-by: Rob Herring diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 747fd3f689dc..a572c3468226 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -52,6 +52,8 @@ properties: - at,24c08 # i2c trusted platform module (TPM) - atmel,at97sc3204t + # i2c h/w symmetric crypto module + - atmel,atsha204a # CM32181: Ambient Light Sensor - capella,cm32181 # CM3232: Ambient Light Sensor