From patchwork Tue Apr 30 16:29:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 10923949 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5A73A92A for ; Tue, 30 Apr 2019 16:29:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4A1FD28769 for ; Tue, 30 Apr 2019 16:29:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3DEC6288A9; Tue, 30 Apr 2019 16:29:49 +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=-5.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, SUSPICIOUS_RECIPS autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8800728769 for ; Tue, 30 Apr 2019 16:29:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726694AbfD3Q3s (ORCPT ); Tue, 30 Apr 2019 12:29:48 -0400 Received: from mail-wr1-f68.google.com ([209.85.221.68]:37498 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726448AbfD3Q3r (ORCPT ); Tue, 30 Apr 2019 12:29:47 -0400 Received: by mail-wr1-f68.google.com with SMTP id r6so21781692wrm.4 for ; Tue, 30 Apr 2019 09:29:46 -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=XAG/7MBNQKcnyRwTABVR+nnLiDuF8S7/Ttp9kLBqJQA=; b=X4pJCHvvH1jl7YriWnYI3P6pm05wYYAwtB5o4CMqVQbMFjXTWi0UDOYoj945mXUEhT d/Qzk8ICzQbu/2WivlhGUtzSuhULo5NGEHAGmdgBIsGxXt0SUmIMxLmcTX7/e4/ZRXNr qyyO+Yt35VNI0JYwsDQJB0vrIJN/T3pLTy6DlbXBs4p1oSAO0of5HKj4ds5ZvRw9Rqmz aX2G/zIyFb1FQAPPvWv4JsYrgr2qtVLn2XuGFduwBcJvcRC/Yp/2Pz1ssb++QZAM9cRd zwBWsYWbyiIkk5pPMPjGxJPpVphCHmRawZeUToVWC0BMG3epM5yYyPyEp0uFGAsmoWed nxCg== 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=XAG/7MBNQKcnyRwTABVR+nnLiDuF8S7/Ttp9kLBqJQA=; b=p78jH9GDBhnKNAD8Qqi1VRBeGEoFdBkQOQ18qimZjhf8QdE12NwP9CpD+0d4FyjOKp SqZhJIfdK+Z2bNWHfeq6QhdgDRHyc8gDTX30/asnNgQKd2Wx99vNDSrb5FfuEafwHm8T sz78M+Kp+bYJ4Dm7cgw9kR3NnJcyu7952ahFoX4EQfxZxj9DX9DWH/1iHIEX+yzlS4DN vwFGxhMqDJ1kwvTJTsxqm/Sf3LN2oWgEw8sQPfTUly7sBPp3eeoQc95PFosb42T4FFEN 17q9PRu5BJQxrXnw86TFKZZ7jn31hh11hSnxt6C6c0l+lC8H0zucXchIh8eC/Y+tvLsZ mzCg== X-Gm-Message-State: APjAAAWjf1ohvm9iCRDFzhoeZFEHqLl5RS9T79iE0e/3XRl56B9vT5vZ 0dyaZVzPvbuzbgY3LE0I5vjP5Blz2qTFig== X-Google-Smtp-Source: APXvYqwwUKVo8dN+hu0W322cYGbaZaoO+o1yIqu5vND3Xr90ukmMX12QXn38I8REPelGYGocceQSzQ== X-Received: by 2002:adf:ebd0:: with SMTP id v16mr18190336wrn.175.1556641785176; Tue, 30 Apr 2019 09:29:45 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:1ca3:6afc:30c:1068]) by smtp.gmail.com with ESMTPSA id t67sm5848890wmg.0.2019.04.30.09.29.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 30 Apr 2019 09:29:44 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linus.walleij@linaro.org, joakim.bech@linaro.org, Ard Biesheuvel , Mika Westerberg Subject: [PATCH 1/5] i2c: acpi: permit bus speed to be discovered after enumeration Date: Tue, 30 Apr 2019 18:29:05 +0200 Message-Id: <20190430162910.16771-2-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190430162910.16771-1-ard.biesheuvel@linaro.org> References: <20190430162910.16771-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Cc: Mika Westerberg Signed-off-by: Ard Biesheuvel Acked-by: Mika Westerberg --- drivers/i2c/i2c-core-acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 Tue Apr 30 16:29:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 10923951 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5EFB192A for ; Tue, 30 Apr 2019 16:29:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4ED5328769 for ; Tue, 30 Apr 2019 16:29:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 42AF6288A9; Tue, 30 Apr 2019 16:29:50 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DA12928769 for ; Tue, 30 Apr 2019 16:29:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726448AbfD3Q3t (ORCPT ); Tue, 30 Apr 2019 12:29:49 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:41920 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726028AbfD3Q3s (ORCPT ); Tue, 30 Apr 2019 12:29:48 -0400 Received: by mail-wr1-f67.google.com with SMTP id c12so21740863wrt.8 for ; Tue, 30 Apr 2019 09:29:47 -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=wHdMgh05X5RySoTsMAgv4VWozpEYjOO1CNr0hCQjnMI=; b=YNoNPHIYlhOHy5BbiESIrSs5mP4dL7RkV+WQhY0iIZ2aTAH5yJglhjF/aZJFFXhhb6 YG68LGDZPu9NFGeYrlni84yvoKJLYSDmWmKXk+6O6UE0dCvbhqclYFQ3QkXH/B7bIm2C 8wiv9eggkeesBqh9vtm8Savbeht7l/c1LkkLd8te/2kIu07rOaUcGmtrefxPAl6S4Csr S6E+sfYt9NlsaQ11rhaF1Kq9mElWI2fmN5VtFNgFtxv1Z4wxICQdAKlHW3BZaQKXIRmd k/9f3ordMFRQO97TBpOxUjhZaiP7GEfAS3pdsyhdW8vZmXTS9eOzRO7pkXq3aLKM0Ehd X+vQ== 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=wHdMgh05X5RySoTsMAgv4VWozpEYjOO1CNr0hCQjnMI=; b=ddugyb9fkEm2KLyL0qyl02NdsyxZgJ/RxHfO3q+mlyEMqR3AraR3setB6bP7WVR643 4kx14dEi2DCtRRssBbZBUamU8FxEEC0qrW2v9V7vOYGnfFzS0Q5zkzUUA0uQ0JYKYMZT Gc6518qPPk4RFSe50Xsj0P4N2BaV2uJwJnPAM7SwBUgynOm2MCOnJHOJdxo4/xp20H7o eZRjn20Rhi5Qc0Yuu1hhaZwQcT7voe60QvvU0xf1uPJCRPvdS5ClpJ1/GNhxpJJSMbK3 tSrIpe3Y1F4nN1bL42OZEo/CJskmLtqa/Ge97o5R5A8NXKE3uD5YGaLmpUoat+/OhENe XtCg== X-Gm-Message-State: APjAAAVV81tmmUHtFv8ee34IltFgvAgE//5gyp+gx7qm1eafcRAYaYEO Q/OYQKdK01IVmAZClw21j586qwEzS20BUA== X-Google-Smtp-Source: APXvYqxc+FxQYD3Ixi+POp1EZQ6x7Ndehssi2GBNN0ehouv+vtnvpfe6TxMLvR4f4mUOOFc5SmwgXA== X-Received: by 2002:adf:f7cd:: with SMTP id a13mr30802602wrq.289.1556641786342; Tue, 30 Apr 2019 09:29:46 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:1ca3:6afc:30c:1068]) by smtp.gmail.com with ESMTPSA id t67sm5848890wmg.0.2019.04.30.09.29.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 30 Apr 2019 09:29:45 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linus.walleij@linaro.org, joakim.bech@linaro.org, Ard Biesheuvel Subject: [PATCH 2/5] crypto: atmel-ecc: add support for ACPI probing on non-AT91 platforms Date: Tue, 30 Apr 2019 18:29:06 +0200 Message-Id: <20190430162910.16771-3-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190430162910.16771-1-ard.biesheuvel@linaro.org> References: <20190430162910.16771-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0be55fcc19ba..4c95567e188f 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -530,7 +530,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 Tue Apr 30 16:29:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 10923959 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A101F17DF for ; Tue, 30 Apr 2019 16:29:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8CE8828445 for ; Tue, 30 Apr 2019 16:29:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 80D5F28726; Tue, 30 Apr 2019 16:29:54 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9922228445 for ; Tue, 30 Apr 2019 16:29:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726709AbfD3Q3w (ORCPT ); Tue, 30 Apr 2019 12:29:52 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:50750 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726028AbfD3Q3v (ORCPT ); Tue, 30 Apr 2019 12:29:51 -0400 Received: by mail-wm1-f66.google.com with SMTP id p21so4525364wmc.0 for ; Tue, 30 Apr 2019 09:29:49 -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=oyga+Ie7xiEWrGyl5+PDEjqB3s6bJoV1SQHUBCjSza8=; b=hi5KttShuPue5uCTjfzdsBN1A7WeJjEewJ/t3Mtm0qEfn8NqqGxnh7ANv3rdx9i22o yXIijjMlk1VUwibBOIjX8hJG/N/Idi7H8MaTmLuHgY4RMLM6nDnvpHecT+vsj0ibe/Xx ulRtWpLGvYk0ZnpdHMe+JOVKvtRbRrR/D5xwMr+UA/VUsz5k8fkGl7z/TcOqrO3FVggG OeoKjJ07GZbKmzVgIyiB1fvHV+pE6UmMxaLqgCAQbxYJNZsuTOKCHf8a9mvqlmt0s7hN tutlD8ezMakzikDyHdFwi1URXPsKc1JeOE9N67TLd9hBVkfjPIpys0hUg3oh4ODO7ZwZ HRPg== 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=oyga+Ie7xiEWrGyl5+PDEjqB3s6bJoV1SQHUBCjSza8=; b=e8DbdXIjFUNbPQUBBarcDwIkRoTXQVDCuZUOmDrN11yybrqjan/XJkasc/kFcYoU2J n9on1v9u6pyz7+gQ+yi6H+vuOfqZyaXlYxOoQODX12ToppDd/h3fjtCW0pv4WWvCH8Kf xzK3FHOvr8Hf3Vr9AeZvZIhh8cwviL+4JdwHGfHCoOfTL7XNhY+p/6k//fwM4S+IW5m9 Tyrx2F7VulzsyMhMqqeBbqvTVjeFQ3I12JSDkMYwp/yc2Qiw7O+vjZmdTllnv2Vnaw6b HvWSrsg5qVp0++YA0B5plCUnChRs95EK9EqQ9lfQPdy1cqMEHCBARc8AJ0kFOcCwunEx aexg== X-Gm-Message-State: APjAAAUXUiIvAjBZ8zQ1eERCGJjkcWUZLl24zhbR0oq4ZadDTKu9uLF7 9LoiHgUnFbhXZzTjVM2Y6LYDhAxNVRlZkw== X-Google-Smtp-Source: APXvYqzCsAQc0TN9tFl0JV8Ea11FXTiTCdlfS7w5g0lt0BjnmCDDQv9A7L8cWxCaRN3KrjMETFNREw== X-Received: by 2002:a1c:35c3:: with SMTP id c186mr3982584wma.135.1556641787748; Tue, 30 Apr 2019 09:29:47 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:1ca3:6afc:30c:1068]) by smtp.gmail.com with ESMTPSA id t67sm5848890wmg.0.2019.04.30.09.29.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 30 Apr 2019 09:29:46 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linus.walleij@linaro.org, joakim.bech@linaro.org, Ard Biesheuvel Subject: [PATCH 3/5] crypto: atmel-ecc: factor out code that can be shared Date: Tue, 30 Apr 2019 18:29:07 +0200 Message-Id: <20190430162910.16771-4-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190430162910.16771-1-ard.biesheuvel@linaro.org> References: <20190430162910.16771-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Ard Biesheuvel Reviewed-by: Linus Walleij --- 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(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 4c95567e188f..11b0de15a99d 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -528,9 +528,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 8e7e225d2446..85be01afcc41 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 Tue Apr 30 16:29:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 10923957 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 629631395 for ; Tue, 30 Apr 2019 16:29:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5108428712 for ; Tue, 30 Apr 2019 16:29:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 45A4128726; Tue, 30 Apr 2019 16:29:54 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 738B828769 for ; Tue, 30 Apr 2019 16:29:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726706AbfD3Q3w (ORCPT ); Tue, 30 Apr 2019 12:29:52 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:55681 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726698AbfD3Q3w (ORCPT ); Tue, 30 Apr 2019 12:29:52 -0400 Received: by mail-wm1-f66.google.com with SMTP id o25so4497037wmf.5 for ; Tue, 30 Apr 2019 09:29:50 -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=itoYXLY0qE+ThxcYSqGsicVXex5g/IXdD9HmYKoxPew=; b=FGEyivk0RaQ9D4pFAwIzdCny3eiHOixy20MzQYhQfkkz3blNodYBYZHMrUuy+/Ohhs MEgpkRXZMkKVMiEXPr/Z5N/LChzW4LlunO41LN+ZhCr5Ob+9RgD1IfeG0ODhUeeHuvds qK6dHyeiA4DF8oxl0nBThqB8E/1/IIUjuora4XydKUcgQCbDiX6Y1naOUNCZ6r5Ame+F V924j1bKt5IKubL8oG9u37wb61Dqjmk8Rqd+Gfl6A8LaTrorgb9+xVjHduFIhUMowqo4 izZ0KyJVX4AhwbtZ88myyKbyi2PZEljTJE3M2aGW7IGkiZoSP33XCVTbIti7eoNbF3us CFYQ== 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=itoYXLY0qE+ThxcYSqGsicVXex5g/IXdD9HmYKoxPew=; b=ctbSamKQYEHdk7Ktusl3pm/TVVKTQrrdGVihSlMdXknTTfF1SQ9FgMonDxQHr6SnAu /sW9oFFul9ns7VS4xIKCyzD5HiFj8qq3X+eKjXlzTQRxRspyyOn6QtkrfVjumBxJxvJ1 WWoYMNtqNnuzFMGrz5t2mOR3sQoCFnm2awkClydwC71sfT8SlR9Qu9nZfyep/jcEk0Xv LC//G8yJ22kJ172di6FKXPERjcFSlrgSQgS/4j/QX3frLquYV8GmsIO+e/ZlGiHnYUpP DngXGurGl43znjxIE5EftfPHfisd9Qcc/4krIM2B0farmIv5+0/xRZ23DqFFQf4fMBmH +dBg== X-Gm-Message-State: APjAAAUUhosGv0h16wTfxF+8qq86wUiccNzepG2yK7l8gb67BTX+QU+z wHabqeaqYjtITVrhxJQHtKZe7LbE3RFJYQ== X-Google-Smtp-Source: APXvYqyNVC0pizV1lUNjkQ9pjQV0ZPJvdBq/9bUeOSrV1j/3DV8sCrArM8VRKUZPizpMU8Qeq/CpnA== X-Received: by 2002:a1c:b782:: with SMTP id h124mr3948711wmf.5.1556641789118; Tue, 30 Apr 2019 09:29:49 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:1ca3:6afc:30c:1068]) by smtp.gmail.com with ESMTPSA id t67sm5848890wmg.0.2019.04.30.09.29.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 30 Apr 2019 09:29:48 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linus.walleij@linaro.org, joakim.bech@linaro.org, Ard Biesheuvel Subject: [PATCH 4/5] crypto: atmel-i2c: add support for SHA204A random number generator Date: Tue, 30 Apr 2019 18:29:08 +0200 Message-Id: <20190430162910.16771-5-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190430162910.16771-1-ard.biesheuvel@linaro.org> References: <20190430162910.16771-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Ard Biesheuvel Reviewed-by: Linus Walleij --- 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(+) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 11b0de15a99d..fe143d6c6050 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -545,6 +545,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 85be01afcc41..5d054ffa8814 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 Tue Apr 30 16:29:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 10923953 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BA2B4912 for ; Tue, 30 Apr 2019 16:29:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AB88828726 for ; Tue, 30 Apr 2019 16:29:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9FF3D287E0; Tue, 30 Apr 2019 16:29:53 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5124028712 for ; Tue, 30 Apr 2019 16:29:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726028AbfD3Q3w (ORCPT ); Tue, 30 Apr 2019 12:29:52 -0400 Received: from mail-wr1-f66.google.com ([209.85.221.66]:43411 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726706AbfD3Q3w (ORCPT ); Tue, 30 Apr 2019 12:29:52 -0400 Received: by mail-wr1-f66.google.com with SMTP id a12so21734804wrq.10 for ; Tue, 30 Apr 2019 09:29:51 -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=OZdMMD/d049PgXvrPSeOT8GlS+Kf7F/BVLM3iDmEjB8=; b=x32olgjIsDKXQnqTef0bHOIbkN+qEu+CC1h3ZDHczaZ96TaV8ivC5H1+nU6friSHZR wvWou7IHHUYvYPgeSYtMofzMQQeH2lxl/8AJ3iA94pZrovItQazLuZ82zMyR7JqCjOc/ ulrgiyFNbu7uMkBSwNGBG7fDhaCIhoQ5gLtIzbb45epmrY6iDxAjYQJnXfMmcALo+HmV 3yozRVBYQHAaI9LbtC2/ctgCLyKsAUzUJPm+psF4gR/4rIYBalStPMNzQr1h1aYlbnP5 16enTDW5eA/jlVqVTTNKetDNNrYfoWYOssu7Hciu0sJd7QWFDFdoF9dYbHpCLsGKnYYq 1WSw== 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=OZdMMD/d049PgXvrPSeOT8GlS+Kf7F/BVLM3iDmEjB8=; b=dTN1hhfK1GcL4l8a3YO5GtnOZZhGY+kEF34NHqHWa1jCPO+EJGJXoIChnYMvTzWt2z FCPn3+54zkQrR1WHhi6Fg5pxZhZCC3PHxVNv0DJEaemPj61+0IogGHCANpu9EMllILpW cXe8Zhdg5Bmx86Ap0GkhZhhxHmpgysnPr48fKXK4m35dsakVBXUREX/H3S1QF7Rb+a1s OyLJ3HOTBO2hzopQlrIDG0MF8fqr6nmjaGLyEhkfyztftCbsmlWEaJp8bbw/oHEDkFa0 sRphWcAjO0/sEliw5P0F1YAXuFFJPjSzTf7mTXSYr1A8ul2h/DGDmYiNtpFzSKUlbdwL x/Mw== X-Gm-Message-State: APjAAAXKDztCOK5L8E4tciKrxkt7UfQmS6KTJ3ofIzh3W4zzHehbP6dV MHaUoJG2iv+ecnKhOZWFUr85jIXqw45kdw== X-Google-Smtp-Source: APXvYqw3NRFWUcmKzt4tqocuhkSBoEawVFKii/IxnIPTo2/dCKgJdIaHgwPYMyDFehYGMUXKEN/4uw== X-Received: by 2002:adf:e486:: with SMTP id i6mr7676077wrm.42.1556641790585; Tue, 30 Apr 2019 09:29:50 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:1ca3:6afc:30c:1068]) by smtp.gmail.com with ESMTPSA id t67sm5848890wmg.0.2019.04.30.09.29.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 30 Apr 2019 09:29:49 -0700 (PDT) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linus.walleij@linaro.org, joakim.bech@linaro.org, Ard Biesheuvel , Rob Herring , Mark Rutland Subject: [PATCH 5/5] dt-bindings: add Atmel SHA204A I2C crypto processor Date: Tue, 30 Apr 2019 18:29:09 +0200 Message-Id: <20190430162910.16771-6-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190430162910.16771-1-ard.biesheuvel@linaro.org> References: <20190430162910.16771-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a compatible string for the Atmel SHA204A I2C crypto processor. Cc: Rob Herring Cc: Mark Rutland Signed-off-by: Ard Biesheuvel Reviewed-by: Linus Walleij --- Documentation/devicetree/bindings/crypto/atmel-crypto.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt index 6b458bb2440d..a93d4b024d0e 100644 --- a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt +++ b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt @@ -79,3 +79,16 @@ atecc508a@c0 { compatible = "atmel,atecc508a"; reg = <0xC0>; }; + +* Symmetric Cryptography (I2C) + +Required properties: +- compatible : must be "atmel,atsha204a". +- reg: I2C bus address of the device. +- clock-frequency: must be present in the i2c controller node. + +Example: +atsha204a@c0 { + compatible = "atmel,atsha204a"; + reg = <0xC0>; +};