@@ -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;
@@ -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 */
@@ -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) {
@@ -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