diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index f9e87fb33da0382c6445c20981b22cddb56929f1..7ec40c4b2d5af7eed077e5eae4968ab2f5789845 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -209,6 +209,7 @@ struct sja1105_private { unsigned long ucast_egress_floods; unsigned long bcast_egress_floods; const struct sja1105_info *info; + size_t max_xfer_len; struct gpio_desc *reset_gpio; struct spi_device *spidev; struct dsa_switch *ds; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 405024b637d6c0ee43034653f2368fdf2f239753..802314e90e64121dd055d740481780b60546c148 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -3563,6 +3563,7 @@ static int sja1105_probe(struct spi_device *spi) struct sja1105_tagger_data *tagger_data; struct device *dev = &spi->dev; struct sja1105_private *priv; + size_t max_xfer, max_msg; struct dsa_switch *ds; int rc, port; @@ -3596,6 +3597,33 @@ static int sja1105_probe(struct spi_device *spi) return rc; } + /* In sja1105_xfer, we send spi_messages composed of two spi_transfers: + * a small one for the message header and another one for the current + * chunk of the packed buffer. + * Check that the restrictions imposed by the SPI controller are + * respected: the chunk buffer is smaller than the max transfer size, + * and the total length of the chunk plus its message header is smaller + * than the max message size. + * We do that during probe time since the maximum transfer size is a + * runtime invariant. + */ + max_xfer = spi_max_transfer_size(spi); + max_msg = spi_max_message_size(spi); + + /* We need to send at least one 64-bit word of SPI payload per message + * in order to be able to make useful progress. + */ + if (max_msg < SJA1105_SIZE_SPI_MSG_HEADER + 8) { + dev_err(dev, "SPI master cannot send large enough buffers, aborting\n"); + return -EINVAL; + } + + priv->max_xfer_len = SJA1105_SIZE_SPI_MSG_MAXLEN; + if (priv->max_xfer_len > max_xfer) + priv->max_xfer_len = max_xfer; + if (priv->max_xfer_len > max_msg - SJA1105_SIZE_SPI_MSG_HEADER) + priv->max_xfer_len = max_msg - SJA1105_SIZE_SPI_MSG_HEADER; + priv->info = of_device_get_match_data(dev); /* Detect hardware device */ diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 8746e3f158a067defe4c7b79561d1014aa83eae8..5a7b404bf3ce14f592f674ea3e0260dff9d8cd75 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -8,8 +8,6 @@ #include "sja1105.h" #define SJA1105_SIZE_RESET_CMD 4 -#define SJA1105_SIZE_SPI_MSG_HEADER 4 -#define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4) struct sja1105_chunk { u8 *buf; @@ -40,19 +38,19 @@ static int sja1105_xfer(const struct sja1105_private *priv, size_t len, struct ptp_system_timestamp *ptp_sts) { u8 hdr_buf[SJA1105_SIZE_SPI_MSG_HEADER] = {0}; - 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[2] = {0}; struct spi_transfer *chunk_xfer; struct spi_transfer *hdr_xfer; + struct sja1105_chunk chunk; int num_chunks; int rc, i = 0; - num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN); + num_chunks = DIV_ROUND_UP(len, priv->max_xfer_len); + + chunk.reg_addr = reg_addr; + chunk.buf = buf; + chunk.len = min_t(size_t, len, priv->max_xfer_len); hdr_xfer = &xfers[0]; chunk_xfer = &xfers[1]; @@ -104,7 +102,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); + priv->max_xfer_len); rc = spi_sync_transfer(spi, xfers, 2); if (rc < 0) { diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h index bc76068992899920a5a403c4e73c0737226ccc58..779eb6840f05b6e9174921723f02319738f1a65c 100644 --- a/drivers/net/dsa/sja1105/sja1105_static_config.h +++ b/drivers/net/dsa/sja1105/sja1105_static_config.h @@ -9,6 +9,8 @@ #include <linux/types.h> #include <asm/types.h> +#define SJA1105_SIZE_SPI_MSG_HEADER 4 +#define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4) #define SJA1105_SIZE_DEVICE_ID 4 #define SJA1105_SIZE_TABLE_HEADER 12 #define SJA1105_SIZE_SCHEDULE_ENTRY 8