From patchwork Wed Nov 18 21:19:29 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heiner Kallweit X-Patchwork-Id: 7652721 Return-Path: X-Original-To: patchwork-linux-spi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C7F1DBF90C for ; Wed, 18 Nov 2015 21:19:50 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C2DD6204D5 for ; Wed, 18 Nov 2015 21:19:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0A9C6204D1 for ; Wed, 18 Nov 2015 21:19:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756999AbbKRVTr (ORCPT ); Wed, 18 Nov 2015 16:19:47 -0500 Received: from mail-wm0-f44.google.com ([74.125.82.44]:37914 "EHLO mail-wm0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756802AbbKRVTq (ORCPT ); Wed, 18 Nov 2015 16:19:46 -0500 Received: by wmec201 with SMTP id c201so91604297wme.1 for ; Wed, 18 Nov 2015 13:19:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=to:cc:from:subject:message-id:date:user-agent:mime-version :content-type:content-transfer-encoding; bh=HnSUR0onydnhzAiu1Tp74G/IBZjoll7LsiET8QmM8wU=; b=eGXq5im/XExSJJly6jfFDOsVjF3f8HSqtxFV7Ck7o+qyCnmrF5IqmsXqdyAg22QKAh JFk5yHwK8nhZrexqKc3FUy+fbVTUu6ULLQRORUkqAvPffUV9xhX5gMn0WofyiPGPAP9Q Ipd+7kLUdDYBFzbyy8D19SHt1vkL9EUEMaW65WuAvuamT09hV66sTBJ6sLogiZSDHGlj I0LjU4BeGrX+MdJA36I0s6DfNMXgAgwo908LLbXCc/XAVZqIEVMOrDGs9zqDcnAY7gRU cRxay2fKQeoydpnXyXhk5J6VbwA30ZRw7+5G2baTtTs7U3zvAK548mW1zg4cXN/y0HUb QhJg== X-Received: by 10.194.134.72 with SMTP id pi8mr4131542wjb.34.1447881585612; Wed, 18 Nov 2015 13:19:45 -0800 (PST) Received: from ?IPv6:2003:62:5f55:ba00:59b1:367b:d148:d70b? (p200300625F55BA0059B1367BD148D70B.dip0.t-ipconnect.de. [2003:62:5f55:ba00:59b1:367b:d148:d70b]) by smtp.googlemail.com with ESMTPSA id 5sm17287949wmx.23.2015.11.18.13.19.44 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 18 Nov 2015 13:19:44 -0800 (PST) To: Brian Norris Cc: Mark Brown , linux-mtd@lists.infradead.org, "linux-spi@vger.kernel.org" From: Heiner Kallweit Subject: RfC: Handle SPI controller limitations like maximum message length Message-ID: <564CEB61.2000601@gmail.com> Date: Wed, 18 Nov 2015 22:19:29 +0100 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 MIME-Version: 1.0 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There have been few discussions in the past about how to handle SPI controller limitations like max message length. However they don't seem to have resulted in accepted patches yet. I also stumbled across this topic because I own a device using Freescale's ESPI which has a 64K message size limitation. At least one agreed fact is that silently assembling chunks in protocol drivers is not the preferred approach. Maybe a better approach would be to introduce a new member of spi_master dealing with controller limitations. My issue is just the message size limitation but most likely there are more and different limitations in other controllers. I'd introduce a struct spi_controller_restrictions and add a member to spi_master pointing to such a struct. Then a controller driver could do something like this: static const struct spi_controller_restrictions fsl_espi_restrictions = { .max_msg_size = 0xffff, }; master->restrictions = &fsl_espi_restrictions; I also add an example how a protocol driver could use this extension. Appreciate any comment. diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 269e8af..8a27c66 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -276,6 +276,17 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) spi_unregister_driver) /** + * struct spi_controller_restrictions - restrictions of the controller + * @max_msg_size: maximum length of a SPI message + * SPI controllers can have different restrictions like a maximum + * supported message size. + * This struct most likely is going to be extended over time. + */ +struct spi_controller_restrictions { + size_t max_msg_size; +}; + +/** * struct spi_master - interface to SPI master controller * @dev: device interface to this driver * @list: link with the global spi_master list @@ -295,6 +306,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @min_speed_hz: Lowest supported transfer speed * @max_speed_hz: Highest supported transfer speed * @flags: other constraints relevant to this driver + * @restrictions: controller restrictions like max supported message size * @bus_lock_spinlock: spinlock for SPI bus locking * @bus_lock_mutex: mutex for SPI bus locking * @bus_lock_flag: indicates that the SPI bus is locked for exclusive use @@ -417,6 +429,9 @@ struct spi_master { #define SPI_MASTER_MUST_RX BIT(3) /* requires rx */ #define SPI_MASTER_MUST_TX BIT(4) /* requires tx */ + /* collection of restrictions like max supported message size */ + struct spi_controller_restrictions *restrictions; + /* lock and mutex for SPI bus locking */ spinlock_t bus_lock_spinlock; struct mutex bus_lock_mutex; -- 2.6.2 --- drivers/mtd/devices/m25p80.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index f10daa8..0e46fb1f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -115,11 +115,7 @@ static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor) } } -/* - * Read an address range from the nor chip. The address range - * may be any size provided it is within the physical boundaries. - */ -static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, +static int _m25p80_read(struct spi_nor *nor, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct m25p *flash = nor->priv; @@ -160,6 +156,41 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, return ret; } +/* + * Read an address range from the nor chip. The address range + * may be any size provided it is within the physical boundaries. + */ +static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct m25p *flash = nor->priv; + struct spi_controller_restrictions *restrictions = + flash->spi->master->restrictions; + size_t cmd_len, xfer_len, max_len; + int ret = 0; + + /* convert the dummy cycles to the number of bytes */ + cmd_len = m25p_cmdsz(nor) + nor->read_dummy / 8; + + max_len = (restrictions && restrictions->max_msg_size) ? + restrictions->max_msg_size : SIZE_MAX; + + if (unlikely(max_len < cmd_len)) + return -EINVAL; + + max_len -= cmd_len; + + while (len) { + xfer_len = min(len, max_len); + ret = _m25p80_read(nor, from, xfer_len, retlen, buf); + if (ret < 0) + break; + from += xfer_len; + len -= xfer_len; + } + + return ret; +} + static int m25p80_erase(struct spi_nor *nor, loff_t offset) { struct m25p *flash = nor->priv;