[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210520135031.2969183-1-olteanv@gmail.com>
Date: Thu, 20 May 2021 16:50:31 +0300
From: Vladimir Oltean <olteanv@...il.com>
To: Jakub Kicinski <kuba@...nel.org>,
"David S. Miller" <davem@...emloft.net>, netdev@...r.kernel.org
Cc: Florian Fainelli <f.fainelli@...il.com>,
Andrew Lunn <andrew@...n.ch>,
Vivien Didelot <vivien.didelot@...il.com>,
Mark Brown <broonie@...nel.org>, linux-spi@...r.kernel.org,
Guenter Roeck <linux@...ck-us.net>,
Vladimir Oltean <vladimir.oltean@....com>
Subject: [PATCH net-next] net: dsa: sja1105: adapt to a SPI controller with a limited max transfer size
From: Vladimir Oltean <vladimir.oltean@....com>
The static config of the sja1105 switch is a long stream of bytes which
is programmed to the hardware in chunks (portions with the chip select
continuously asserted) of max 256 bytes each.
Only that certain SPI controllers, such as the spi-sc18is602 I2C-to-SPI
bridge, cannot keep the chip select asserted for that long.
The spi_max_transfer_size() and spi_max_message_size() functions are how
the controller can impose its hardware limitations upon the SPI
peripheral driver.
The sja1105 sends its static config to the SPI master as a huge
scatter/gather spi_message - commit 08839c06e96f ("net: dsa: sja1105:
Switch to scatter/gather API for SPI") contains a description of that.
That spi_message contains the following list of spi_transfers:
| | cs_change
spi_transfer # | Contents | (deassert chip select)
---------------|-------------------------|-----------------------
1 | SPI message header 1 | no
2 | Static config chunk 1 | yes
3 | SPI message header 2 | no
4 | Static config chunk 2 | yes
... | ... | ...
Since what the SPI master does not support is keeping the CS asserted
for more than, say, 200 bytes, we must limit the summed length of the
spi_transfers with cs_change deasserted (1+2, 3+4 etc) lower than 200.
This is a bit fuzzy, but I think the proper way to handle this is to
just look at the spi_max_transfer_size() reported by the master, and
adapt to that. We can disregard the spi_max_message_size() limit since I
suppose that assumes no cs_change - but then again, spi_max_transfer_size
is itself capped by spi_max_message_size, which makes sense.
Regression-tested on a switch connected to a controller with no
limitations (spi-fsl-dspi) as well as with one with caps for both
max_transfer_size and max_message_size (spi-sc18is602).
Signed-off-by: Vladimir Oltean <vladimir.oltean@....com>
---
drivers/net/dsa/sja1105/sja1105_spi.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c
index f7a1514f81e8..ac766def45c8 100644
--- a/drivers/net/dsa/sja1105/sja1105_spi.c
+++ b/drivers/net/dsa/sja1105/sja1105_spi.c
@@ -46,18 +46,22 @@ static int sja1105_xfer(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 reg_addr, u8 *buf,
size_t len, struct ptp_system_timestamp *ptp_sts)
{
+ struct spi_device *spi = priv->spidev;
struct sja1105_chunk chunk = {
- .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN),
.reg_addr = reg_addr,
.buf = buf,
};
- struct spi_device *spi = priv->spidev;
struct spi_transfer *xfers;
+ size_t xfer_len;
int num_chunks;
int rc, i = 0;
u8 *hdr_bufs;
- num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN);
+ xfer_len = min_t(size_t, SJA1105_SIZE_SPI_MSG_MAXLEN,
+ spi_max_transfer_size(spi) - SJA1105_SIZE_SPI_MSG_HEADER);
+
+ num_chunks = DIV_ROUND_UP(len, xfer_len);
+ chunk.len = min(len, xfer_len);
/* One transfer for each message header, one for each message
* payload (chunk).
@@ -127,7 +131,7 @@ static int sja1105_xfer(const struct sja1105_private *priv,
chunk.buf += chunk.len;
chunk.reg_addr += chunk.len / 4;
chunk.len = min_t(size_t, (ptrdiff_t)(buf + len - chunk.buf),
- SJA1105_SIZE_SPI_MSG_MAXLEN);
+ xfer_len);
/* De-assert the chip select after each chunk. */
if (chunk.len)
--
2.25.1
Powered by blists - more mailing lists