From patchwork Wed Feb 24 05:51:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Mosberger-Tang X-Patchwork-Id: 12101317 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E8D54C433E0 for ; Wed, 24 Feb 2021 05:52:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 84DBB64EBA for ; Wed, 24 Feb 2021 05:52:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233880AbhBXFwh (ORCPT ); Wed, 24 Feb 2021 00:52:37 -0500 Received: from o1.ptr2625.egauge.net ([167.89.112.53]:40939 "EHLO o1.ptr2625.egauge.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233711AbhBXFwf (ORCPT ); Wed, 24 Feb 2021 00:52:35 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=egauge.net; h=from:subject:mime-version:to:cc:content-transfer-encoding: content-type; s=sgd; bh=wc+RK5tGmY6FeIzTBNgzRNI0oDBWIJRtwAZQIRgUtTQ=; b=JE9ksbQ4D/ZxB8lmBN5B8Ll9VGYNv3YEtSHepkH/nNQ4s0JqNRLh8Y/hvWKQpmcCZYjs vOsiPD3CBdYDJ4L6xp/KdZpIC1eMlRpqr23dbKSypjquF9Rt7M3DY02h+7fkKyXO3uZNsF l/xvj+qhQtndCisQaP/64pxyPNP99qtnQ= Received: by filterdrecv-p3mdw1-7745b6f999-88clt with SMTP id filterdrecv-p3mdw1-7745b6f999-88clt-18-6035E975-1 2021-02-24 05:51:49.069958647 +0000 UTC m=+617729.431238615 Received: from pearl.egauge.net (unknown) by geopod-ismtpd-5-0 (SG) with ESMTP id Byb5h3xgSJe-dCzQbXU-rw Wed, 24 Feb 2021 05:51:48.850 +0000 (UTC) Received: by pearl.egauge.net (Postfix, from userid 1000) id 2B5067001EB; Tue, 23 Feb 2021 22:51:48 -0700 (MST) From: David Mosberger-Tang Subject: [PATCH 1/4] wilc1000: Make SPI transfers work at 48MHz Date: Wed, 24 Feb 2021 05:51:49 +0000 (UTC) Message-Id: <20210224055135.1509200-1-davidm@egauge.net> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-SG-EID: +kMxBqj35EdRUKoy8diX1j4AXmPtd302oan+iXZuF8m2Nw4HRW2irNspffT/khET6RJF6+Prbl0h/EtF1rRLvKisN36aBfL+MQdq6UUoQJ34yctXSpLeL9JtQ1O2MNVnaCNAFL+k0DBL82qwn38GP9HNQb/t1OUDKQKPhriMNRFu5W4lV4GdKn1lyZ6YRWX68QGTUn4y02T9HnYchgG5/fAxhgUT9eGI4zAduAREdDDo6yLplbGDU7ExALVI8y8l4Ugkbx2Lm8WAnxog+QRclg== To: linux-wireless@vger.kernel.org Cc: Ajay Singh , Claudiu Beznea , davidm@egauge.net X-Entity-ID: Xg4JGAcGrJFIz2kDG9eoaQ== Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org For CMD_SINGLE_READ and CMD_INTERNAL_READ, WILC may insert one or more zero bytes between the command response and the DATA Start tag (0xf3). This behavior appears to be undocumented in "ATWILC1000 USER GUIDE" (https://tinyurl.com/4hhshdts) but we have observed 1-4 zero bytes when the SPI bus operates at 48MHz and none when it operates at 1MHz. This code is derived from the equivalent code of the wilc driver in the linux-at91 repository. Signed-off-by: David Mosberger-Tang --- drivers/net/wireless/microchip/wilc1000/spi.c | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index be732929322c..d11e365eeee2 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -11,6 +11,16 @@ #include "netdev.h" #include "cfg80211.h" +/* + * For CMD_SINGLE_READ and CMD_INTERNAL_READ, WILC may insert one or + * more zero bytes between the command response and the DATA Start tag + * (0xf3). This behavior appears to be undocumented in "ATWILC1000 + * USER GUIDE" (https://tinyurl.com/4hhshdts) but we have observed 1-4 + * zero bytes when the SPI bus operates at 48MHz and none when it + * operates at 1MHz. + */ +#define WILC_SPI_RSP_HDR_EXTRA_DATA 8 + struct wilc_spi { int crc_off; }; @@ -79,16 +89,15 @@ struct wilc_spi_cmd { } __packed; struct wilc_spi_read_rsp_data { - u8 rsp_cmd_type; - u8 status; - u8 resp_header; - u8 resp_data[4]; + u8 header; + u8 data[4]; u8 crc[]; } __packed; struct wilc_spi_rsp_data { u8 rsp_cmd_type; u8 status; + u8 data[]; } __packed; static int wilc_bus_probe(struct spi_device *spi) @@ -359,10 +368,11 @@ static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, struct spi_device *spi = to_spi_device(wilc->dev); struct wilc_spi *spi_priv = wilc->bus_data; u8 wb[32], rb[32]; - int cmd_len, resp_len; u8 crc[2]; + int cmd_len, resp_len, i; struct wilc_spi_cmd *c; - struct wilc_spi_read_rsp_data *r; + struct wilc_spi_read_rsp_data *r_data; + struct wilc_spi_rsp_data *r; memset(wb, 0x0, sizeof(wb)); memset(rb, 0x0, sizeof(rb)); @@ -384,7 +394,8 @@ static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, } cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); - resp_len = sizeof(*r); + resp_len = sizeof(*r) + sizeof(*r_data) + WILC_SPI_RSP_HDR_EXTRA_DATA; + if (!spi_priv->crc_off) { c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); cmd_len += 1; @@ -403,7 +414,7 @@ static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, return -EINVAL; } - r = (struct wilc_spi_read_rsp_data *)&rb[cmd_len]; + r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; if (r->rsp_cmd_type != cmd) { dev_err(&spi->dev, "Failed cmd response, cmd (%02x), resp (%02x)\n", @@ -417,17 +428,22 @@ static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, return -EINVAL; } - if (WILC_GET_RESP_HDR_START(r->resp_header) != 0xf) { - dev_err(&spi->dev, "Error, data read response (%02x)\n", - r->resp_header); + for (i = 0; i < WILC_SPI_RSP_HDR_EXTRA_DATA; ++i) + if (WILC_GET_RESP_HDR_START(r->data[i]) == 0xf) + break; + + if (i >= WILC_SPI_RSP_HDR_EXTRA_DATA) { + dev_err(&spi->dev, "Error, data start missing\n"); return -EINVAL; } + r_data = (struct wilc_spi_read_rsp_data *)&r->data[i]; + if (b) - memcpy(b, r->resp_data, 4); + memcpy(b, r_data->data, 4); if (!spi_priv->crc_off) - memcpy(crc, r->crc, 2); + memcpy(crc, r_data->crc, 2); return 0; } From patchwork Wed Feb 24 05:51:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Mosberger-Tang X-Patchwork-Id: 12101319 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3FD13C433DB for ; Wed, 24 Feb 2021 05:53:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EC2C564EBA for ; Wed, 24 Feb 2021 05:52:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234006AbhBXFwm (ORCPT ); Wed, 24 Feb 2021 00:52:42 -0500 Received: from o1.ptr2625.egauge.net ([167.89.112.53]:47326 "EHLO o1.ptr2625.egauge.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233954AbhBXFwk (ORCPT ); Wed, 24 Feb 2021 00:52:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=egauge.net; h=from:subject:in-reply-to:references:mime-version:to:cc: content-transfer-encoding:content-type; s=sgd; bh=/sxCVuo1phQGlqgitdXTs3sBeAsKQgb46SnH1ErepPY=; b=BGpbOK6NK2pyn/xkMjTAPraPIyvdbSyIDEpd3DCo5mGDYhiogxdW2IBzi0iO/+kSxoPI ce32vB2Qim5uroOxIu+QxVvw2Nbz34oZDoSDjCVq8hBNEu8zh1RYhzsAaFLt6DqccYKtzz gHoURl6dexgnHwxdSpkgVQpM5epVwhtOs= Received: by filterdrecv-p3mdw1-7745b6f999-7qk4c with SMTP id filterdrecv-p3mdw1-7745b6f999-7qk4c-19-6035E97A-F 2021-02-24 05:51:54.595112686 +0000 UTC m=+617733.245676506 Received: from pearl.egauge.net (unknown) by ismtpd0012p1las1.sendgrid.net (SG) with ESMTP id D1VKkarWQbeZkVQKDO7ogg Wed, 24 Feb 2021 05:51:54.406 +0000 (UTC) Received: by pearl.egauge.net (Postfix, from userid 1000) id C90457001EB; Tue, 23 Feb 2021 22:51:53 -0700 (MST) From: David Mosberger-Tang Subject: [PATCH 2/4] wilc1000: Introduce symbolic names for SPI protocol register Date: Wed, 24 Feb 2021 05:51:54 +0000 (UTC) Message-Id: <20210224055135.1509200-2-davidm@egauge.net> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224055135.1509200-1-davidm@egauge.net> References: <20210224055135.1509200-1-davidm@egauge.net> MIME-Version: 1.0 X-SG-EID: +kMxBqj35EdRUKoy8diX1j4AXmPtd302oan+iXZuF8m2Nw4HRW2irNspffT/khET6RJF6+Prbl0h/EtF1rRLvPJB0edtl7ID2WPbp62W5Uzu4C2eQ6tYtHfNWD2DdD5IOkg3AmwOXiCdpGPhx0O/dJwu0DbeAd+do1Wm+l3O6cNpJphgs6quU0GXAeocwpOcPaA1S9YGv4VrJgCTe8nlALXH+irfYLtlmlri88oUzEc8q2Ncpc/TZyF7bCHf7h9MnZgyxxFH/pLcwegY+cl7QA== To: linux-wireless@vger.kernel.org Cc: Ajay Singh , Claudiu Beznea , davidm@egauge.net X-Entity-ID: Xg4JGAcGrJFIz2kDG9eoaQ== Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org The WILC1000 protocol control register has bits for enabling the CRCs (CRC7 for commands and CRC16 for data) and to set the data packet size. Define symbolic names for those so the code is more easily understood. Signed-off-by: David Mosberger-Tang --- drivers/net/wireless/microchip/wilc1000/spi.c | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index d11e365eeee2..fca34d1999ec 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -46,12 +46,25 @@ static const struct wilc_hif_func wilc_hif_spi; #define CMD_RESET 0xcf #define SPI_ENABLE_VMM_RETRY_LIMIT 2 -#define DATA_PKT_SZ_256 256 -#define DATA_PKT_SZ_512 512 -#define DATA_PKT_SZ_1K 1024 -#define DATA_PKT_SZ_4K (4 * 1024) -#define DATA_PKT_SZ_8K (8 * 1024) -#define DATA_PKT_SZ DATA_PKT_SZ_8K + +#define PROTOCOL_REG_PKT_SZ_MASK GENMASK(6, 4) +#define PROTOCOL_REG_CRC16_MASK GENMASK(3, 3) +#define PROTOCOL_REG_CRC7_MASK GENMASK(2, 2) + +/* + * The SPI data packet size may be any integer power of two in the + * range from 256 to 8192 bytes. + */ +#define DATA_PKT_LOG_SZ_MIN 8 /* 256 B */ +#define DATA_PKT_LOG_SZ_MAX 13 /* 8 KiB */ + +/* + * Select the data packet size (log2 of number of bytes): Use the + * maximum data packet size. We only retransmit complete packets, so + * there is no benefit from using smaller data packets. + */ +#define DATA_PKT_LOG_SZ DATA_PKT_LOG_SZ_MAX +#define DATA_PKT_SZ (1 << DATA_PKT_LOG_SZ) #define USE_SPI_DMA 0 @@ -827,9 +840,16 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) } } if (spi_priv->crc_off == 0) { - reg &= ~0xc; /* disable crc checking */ - reg &= ~0x70; - reg |= (0x5 << 4); + /* disable crc checking: */ + reg &= ~(PROTOCOL_REG_CRC7_MASK | PROTOCOL_REG_CRC16_MASK); + + /* set the data packet size: */ + BUILD_BUG_ON(DATA_PKT_LOG_SZ < DATA_PKT_LOG_SZ_MIN + || DATA_PKT_LOG_SZ > DATA_PKT_LOG_SZ_MAX); + reg &= ~PROTOCOL_REG_PKT_SZ_MASK; + reg |= FIELD_PREP(PROTOCOL_REG_PKT_SZ_MASK, + DATA_PKT_LOG_SZ - DATA_PKT_LOG_SZ_MIN); + ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); if (ret) { dev_err(&spi->dev, From patchwork Wed Feb 24 05:51:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Mosberger-Tang X-Patchwork-Id: 12101321 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 637F7C433E0 for ; Wed, 24 Feb 2021 05:53:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 21FE464EBB for ; Wed, 24 Feb 2021 05:53:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233959AbhBXFwp (ORCPT ); Wed, 24 Feb 2021 00:52:45 -0500 Received: from o1.ptr2625.egauge.net ([167.89.112.53]:8934 "EHLO o1.ptr2625.egauge.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233997AbhBXFwn (ORCPT ); Wed, 24 Feb 2021 00:52:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=egauge.net; h=from:subject:in-reply-to:references:mime-version:to:cc: content-transfer-encoding:content-type; s=sgd; bh=ZYC9IQdF3wXzbcLOj7Ji/0m+8iDBvubNR8pDbwfzrRU=; b=fcVbi9rKFMhMALltS4LHXvVuYhdsnrHIpEWA7BretPLqi9Da3zdqtqEKYqDLzYFWKFrf SAGdY9CBsyWr+0bc2sWkHWeg+iOtvHa44z4xFCe0k6A0VG44g7v1NB757PrlVG0wOnYEqM VfvAghs39w4aFLCQe50EiVWvXYmZMZbKo= Received: by filterdrecv-p3iad2-fdf5ff85d-blwrf with SMTP id filterdrecv-p3iad2-fdf5ff85d-blwrf-19-6035E97C-2F 2021-02-24 05:51:56.954915777 +0000 UTC m=+1235063.223905088 Received: from pearl.egauge.net (unknown) by ismtpd0001p1las1.sendgrid.net (SG) with ESMTP id jXXwKammRomwUrHFgj51sg Wed, 24 Feb 2021 05:51:56.805 +0000 (UTC) Received: by pearl.egauge.net (Postfix, from userid 1000) id 51F937001EB; Tue, 23 Feb 2021 22:51:56 -0700 (MST) From: David Mosberger-Tang Subject: [PATCH 3/4] wilc1000: Check for errors at end of DMA write Date: Wed, 24 Feb 2021 05:51:57 +0000 (UTC) Message-Id: <20210224055135.1509200-3-davidm@egauge.net> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224055135.1509200-1-davidm@egauge.net> References: <20210224055135.1509200-1-davidm@egauge.net> MIME-Version: 1.0 X-SG-EID: +kMxBqj35EdRUKoy8diX1j4AXmPtd302oan+iXZuF8m2Nw4HRW2irNspffT/khET6RJF6+Prbl0h/EtF1rRLvFMz3bzXtgDjSqD3vZuBFVN6zKv4yYW0iAoqufrSDaE8U6gC3nhPT/JAasazQWbtSOC4Ex4MDR3Gu8wGCgsLEjb05Y+LRXaNfqQgARxSgpw65RhffqEyGlR6GFJbXJq1S2bTFsRUHmn616cYO3VwIXMQDPqGgSAxJOBWj0em7X7AxWNlUUpSkmI8HLfdFukouw== To: linux-wireless@vger.kernel.org Cc: Ajay Singh , Claudiu Beznea , davidm@egauge.net X-Entity-ID: Xg4JGAcGrJFIz2kDG9eoaQ== Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org After a DMA write to the WILC chip, check for and report any errors. This is based on code from the wilc driver in the linux-at91 repository. Signed-off-by: David Mosberger-Tang --- drivers/net/wireless/microchip/wilc1000/spi.c | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index fca34d1999ec..b0e096a03a28 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -750,6 +750,51 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) return 0; } +static int spi_data_rsp(struct wilc *wilc, u8 cmd) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int result, i; + u8 rsp[4]; + + /* + * The response to data packets is two bytes long. For + * efficiency's sake, wilc_spi_write() wisely ignores the + * responses for all packets but the final one. The downside + * of that optimization is that when the final data packet is + * short, we may receive (part of) the response to the + * second-to-last packet before the one for the final packet. + * To handle this, we always read 4 bytes and then search for + * the last byte that contains the "Response Start" code (0xc + * in the top 4 bits). We then know that this byte is the + * first response byte of the final data packet. + */ + result = wilc_spi_rx(wilc, rsp, sizeof(rsp)); + if (result) { + dev_err(&spi->dev, "Failed bus error...\n"); + return result; + } + + for (i = sizeof(rsp) - 2; i >= 0; --i) + if ((rsp[i] & 0xf0) == 0xc0) + break; + + if (i < 0) { + dev_err(&spi->dev, + "Data packet response missing (%02x %02x %02x %02x)\n", + rsp[0], rsp[1], rsp[2], rsp[3]); + return -1; + } + + /* rsp[i] is the last response start byte */ + + if (rsp[i] != 0xc3 || rsp[i + 1] != 0x00) { + dev_err(&spi->dev, "Data response error (%02x %02x)\n", + rsp[i], rsp[i + 1]); + return -1; + } + return 0; +} + static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) { struct spi_device *spi = to_spi_device(wilc->dev); @@ -777,7 +822,10 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) return result; } - return 0; + /* + * Data response + */ + return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE); } /******************************************** From patchwork Wed Feb 24 05:52:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Mosberger-Tang X-Patchwork-Id: 12101323 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF1A1C433E6 for ; Wed, 24 Feb 2021 05:53:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4B5B460200 for ; Wed, 24 Feb 2021 05:53:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234015AbhBXFwt (ORCPT ); Wed, 24 Feb 2021 00:52:49 -0500 Received: from o1.ptr2625.egauge.net ([167.89.112.53]:13511 "EHLO o1.ptr2625.egauge.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233997AbhBXFwq (ORCPT ); Wed, 24 Feb 2021 00:52:46 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=egauge.net; h=from:subject:in-reply-to:references:mime-version:to:cc: content-transfer-encoding:content-type; s=sgd; bh=Zh3Rdjov8qTVeX3tbNOAnAUj0VCwTpY2otvV0z8BLQ4=; b=TVx6MK5ZPt9I308GJ1gWgpxl9GeGBL813aLtn1c+v0sgul/Dbg6V8uWSMoSFu4aKZe71 /5CF849RSDjK6K9XiZpCmhipltO8Z5ow+p2MH/GUA/M1H3fMT9bA4i11qlHOvR4agaj7XV 0AwvOA7fiXqYXJ+mAMBz8+6oWts1eqAXs= Received: by filterdrecv-p3iad2-fdf5ff85d-fcdlr with SMTP id filterdrecv-p3iad2-fdf5ff85d-fcdlr-19-6035E980-5 2021-02-24 05:52:00.152484731 +0000 UTC m=+1235066.742630587 Received: from pearl.egauge.net (unknown) by geopod-ismtpd-3-0 (SG) with ESMTP id Y5JuSazoSmep2omSJgEVhg Wed, 24 Feb 2021 05:51:59.992 +0000 (UTC) Received: by pearl.egauge.net (Postfix, from userid 1000) id ADBA37001EB; Tue, 23 Feb 2021 22:51:59 -0700 (MST) From: David Mosberger-Tang Subject: [PATCH 4/4] wilc1000: Add support for enabling CRC Date: Wed, 24 Feb 2021 05:52:00 +0000 (UTC) Message-Id: <20210224055135.1509200-4-davidm@egauge.net> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224055135.1509200-1-davidm@egauge.net> References: <20210224055135.1509200-1-davidm@egauge.net> MIME-Version: 1.0 X-SG-EID: +kMxBqj35EdRUKoy8diX1j4AXmPtd302oan+iXZuF8m2Nw4HRW2irNspffT/khET6RJF6+Prbl0h/EtF1rRLvGCCkyeX0TOi4Kmui/R4Lk80b3oD6LhU+wPeB7EWYAMC8dhlTcmywbO9UW9QiOL+B3ASfMwZxKveH1bSyS4o9aHRi0dBnHo8yGBDMhceVgN6vkTUMaInbCXxN3jD3yig5ws29vTmaRfshDZL6szCa6WUagz/9YPYjqrvrla9ZnO6Pm6lUWzKKcuOF8d+uq61tQ== To: linux-wireless@vger.kernel.org Cc: Ajay Singh , Claudiu Beznea , davidm@egauge.net X-Entity-ID: Xg4JGAcGrJFIz2kDG9eoaQ== Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org The driver so far has always disabled CRC protection. This means any data corruption that occurred during the SPI transfers could potentially go unnoticed. This patch adds the macros ENABLE_CRC7 and ENABLE_CRC16 to allow compile-time selection of whether or not CRC7 and CRC16, respectively, should be enabled. The default configuration remains unchanged, with both CRC7 and CRC16 off. Signed-off-by: David Mosberger-Tang --- .../net/wireless/microchip/wilc1000/Kconfig | 1 + drivers/net/wireless/microchip/wilc1000/spi.c | 151 +++++++++++++----- 2 files changed, 108 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/Kconfig b/drivers/net/wireless/microchip/wilc1000/Kconfig index 7f15e42602dd..62cfcdc9aacc 100644 --- a/drivers/net/wireless/microchip/wilc1000/Kconfig +++ b/drivers/net/wireless/microchip/wilc1000/Kconfig @@ -27,6 +27,7 @@ config WILC1000_SPI depends on CFG80211 && INET && SPI select WILC1000 select CRC7 + select CRC_ITU_T help This module adds support for the SPI interface of adapters using WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index b0e096a03a28..c745a440d273 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -7,10 +7,23 @@ #include #include #include +#include #include "netdev.h" #include "cfg80211.h" +/** + * Establish the driver's desired CRC configuration. CRC7 is used for + * command transfers which have no other protection against corruption + * during the SPI transfer. Commands are short so CRC7 is relatively + * cheap. CRC16 is used for data transfers, including network packet + * transfers. Since those transfers can be large, CRC16 is relatively + * expensive. CRC16 is also often redundant as network packets + * typically are protected by their own, higher-level checksum. + */ +#define ENABLE_CRC7 0 /* set to 1 to protect SPI commands with CRC7 */ +#define ENABLE_CRC16 0 /* set to 1 to protect SPI data with CRC16 */ + /* * For CMD_SINGLE_READ and CMD_INTERNAL_READ, WILC may insert one or * more zero bytes between the command response and the DATA Start tag @@ -22,7 +35,8 @@ #define WILC_SPI_RSP_HDR_EXTRA_DATA 8 struct wilc_spi { - int crc_off; + bool crc7_enabled; + bool crc16_enabled; }; static const struct wilc_hif_func wilc_hif_spi; @@ -123,6 +137,10 @@ static int wilc_bus_probe(struct spi_device *spi) if (!spi_priv) return -ENOMEM; + /* WILC chip resets to both CRCs enabled: */ + spi_priv->crc7_enabled = true; + spi_priv->crc16_enabled = true; + ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi); if (ret) { kfree(spi_priv); @@ -303,7 +321,8 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) struct wilc_spi *spi_priv = wilc->bus_data; int ix, nbytes; int result = 0; - u8 cmd, order, crc[2] = {0}; + u8 cmd, order, crc[2]; + u16 crc_calc; /* * Data @@ -345,9 +364,12 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) } /* - * Write Crc + * Write CRC */ - if (!spi_priv->crc_off) { + if (spi_priv->crc16_enabled) { + crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); + crc[0] = crc_calc >> 8; + crc[1] = crc_calc; if (wilc_spi_tx(wilc, crc, 2)) { dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); result = -EINVAL; @@ -381,11 +403,11 @@ static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, struct spi_device *spi = to_spi_device(wilc->dev); struct wilc_spi *spi_priv = wilc->bus_data; u8 wb[32], rb[32]; - u8 crc[2]; int cmd_len, resp_len, i; + u16 crc_calc, crc_recv; struct wilc_spi_cmd *c; - struct wilc_spi_read_rsp_data *r_data; struct wilc_spi_rsp_data *r; + struct wilc_spi_read_rsp_data *r_data; memset(wb, 0x0, sizeof(wb)); memset(rb, 0x0, sizeof(rb)); @@ -409,7 +431,7 @@ static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); resp_len = sizeof(*r) + sizeof(*r_data) + WILC_SPI_RSP_HDR_EXTRA_DATA; - if (!spi_priv->crc_off) { + if (spi_priv->crc7_enabled) { c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); cmd_len += 1; resp_len += 2; @@ -455,8 +477,16 @@ static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, if (b) memcpy(b, r_data->data, 4); - if (!spi_priv->crc_off) - memcpy(crc, r_data->crc, 2); + if (!clockless && spi_priv->crc16_enabled) { + crc_recv = (r_data->crc[0] << 8) | r_data->crc[1]; + crc_calc = crc_itu_t(0xffff, r_data->data, 4); + if (crc_recv != crc_calc) { + dev_err(&spi->dev, "%s: bad CRC 0x%04x " + "(calculated 0x%04x)\n", __func__, + crc_recv, crc_calc); + return -EINVAL; + } + } return 0; } @@ -483,7 +513,7 @@ static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data, c->u.internal_w_cmd.addr[1] = adr; c->u.internal_w_cmd.data = cpu_to_be32(data); cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc); - if (!spi_priv->crc_off) + if (spi_priv->crc7_enabled) c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); } else if (cmd == CMD_SINGLE_WRITE) { c->u.w_cmd.addr[0] = adr >> 16; @@ -491,14 +521,14 @@ static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data, c->u.w_cmd.addr[2] = adr; c->u.w_cmd.data = cpu_to_be32(data); cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc); - if (!spi_priv->crc_off) + if (spi_priv->crc7_enabled) c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); } else { dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd); return -EINVAL; } - if (!spi_priv->crc_off) + if (spi_priv->crc7_enabled) cmd_len += 1; resp_len = sizeof(*r); @@ -536,6 +566,7 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) { struct spi_device *spi = to_spi_device(wilc->dev); struct wilc_spi *spi_priv = wilc->bus_data; + u16 crc_recv, crc_calc; u8 wb[32], rb[32]; int cmd_len, resp_len; int retry, ix = 0; @@ -554,7 +585,7 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) c->u.dma_cmd.size[0] = sz >> 8; c->u.dma_cmd.size[1] = sz; cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc); - if (!spi_priv->crc_off) + if (spi_priv->crc7_enabled) c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) { c->u.dma_cmd_ext.addr[0] = adr >> 16; @@ -564,14 +595,14 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) c->u.dma_cmd_ext.size[1] = sz >> 8; c->u.dma_cmd_ext.size[2] = sz; cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc); - if (!spi_priv->crc_off) + if (spi_priv->crc7_enabled) c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len); } else { dev_err(&spi->dev, "dma read write cmd [%x] not supported\n", cmd); return -EINVAL; } - if (!spi_priv->crc_off) + if (spi_priv->crc7_enabled) cmd_len += 1; resp_len = sizeof(*r); @@ -637,12 +668,35 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) } /* - * Read Crc + * Read CRC */ - if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) { - dev_err(&spi->dev, - "Failed block crc read, bus err\n"); - return -EINVAL; + if (spi_priv->crc16_enabled) { + if (wilc_spi_rx(wilc, crc, 2)) { + dev_err(&spi->dev, + "Failed block crc read, bus err\n"); + return -EINVAL; + } + crc_recv = (crc[0] << 8) | crc[1]; + crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); + if (crc_recv != crc_calc) { + dev_err(&spi->dev, "%s: bad CRC 0x%04x " + "(calculated 0x%04x)\n", __func__, + crc_recv, crc_calc); + + { + u8 byte; + int i; + + for (i = 0; i < 16384; ++i) { + byte = 0; + wilc_spi_rx(wilc, &byte, 1); + if (!byte) + break; + } + } + + return -EINVAL; + } } ix += nbytes; @@ -871,43 +925,52 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); if (ret) { /* - * Read failed. Try with CRC off. This might happen when module - * is removed but chip isn't reset + * Read failed. Try with CRC7 off. This might happen + * when module is removed but chip isn't reset. */ - spi_priv->crc_off = 1; + spi_priv->crc7_enabled = false; dev_err(&spi->dev, - "Failed read with CRC on, retrying with CRC off\n"); + "Failed read with CRC7 on, retrying with CRC7 off\n"); ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); if (ret) { /* - * Read failed with both CRC on and off, + * Read failed with both CRC7 on and off, * something went bad */ dev_err(&spi->dev, "Failed internal read protocol\n"); return ret; } } - if (spi_priv->crc_off == 0) { - /* disable crc checking: */ - reg &= ~(PROTOCOL_REG_CRC7_MASK | PROTOCOL_REG_CRC16_MASK); - - /* set the data packet size: */ - BUILD_BUG_ON(DATA_PKT_LOG_SZ < DATA_PKT_LOG_SZ_MIN - || DATA_PKT_LOG_SZ > DATA_PKT_LOG_SZ_MAX); - reg &= ~PROTOCOL_REG_PKT_SZ_MASK; - reg |= FIELD_PREP(PROTOCOL_REG_PKT_SZ_MASK, - DATA_PKT_LOG_SZ - DATA_PKT_LOG_SZ_MIN); - - ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); - if (ret) { - dev_err(&spi->dev, - "[wilc spi %d]: Failed internal write reg\n", - __LINE__); - return ret; - } - spi_priv->crc_off = 1; + + /* set up the desired CRC configuration: */ + reg &= ~(PROTOCOL_REG_CRC7_MASK | PROTOCOL_REG_CRC16_MASK); +#if ENABLE_CRC7 + reg |= PROTOCOL_REG_CRC7_MASK; +#endif +#if ENABLE_CRC16 + reg |= PROTOCOL_REG_CRC16_MASK; +#endif + + /* set up the data packet size: */ + BUILD_BUG_ON(DATA_PKT_LOG_SZ < DATA_PKT_LOG_SZ_MIN + || DATA_PKT_LOG_SZ > DATA_PKT_LOG_SZ_MAX); + reg &= ~PROTOCOL_REG_PKT_SZ_MASK; + reg |= FIELD_PREP(PROTOCOL_REG_PKT_SZ_MASK, + DATA_PKT_LOG_SZ - DATA_PKT_LOG_SZ_MIN); + + /* establish the new setup: */ + ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); + if (ret) { + dev_err(&spi->dev, + "[wilc spi %d]: Failed internal write reg\n", + __LINE__); + return ret; } + /* now that new set up is established, update our state to match: */ + spi_priv->crc7_enabled = ENABLE_CRC7; + spi_priv->crc16_enabled = ENABLE_CRC16; + /* * make sure can read back chip id correctly */