All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eddie James <eajames@linux.ibm.com>
To: linux-spi@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	eajames@linux.ibm.com, joel@jms.id.au,
	bradleyb@fuzziesquirrel.com, broonie@kernel.org,
	robh+dt@kernel.org, arnd@arndb.de
Subject: [PATCH 7/7] eeprom: at25: Split reads into chunks and cap write size
Date: Thu, 20 Aug 2020 12:02:28 -0500	[thread overview]
Message-ID: <20200820170228.42053-8-eajames@linux.ibm.com> (raw)
In-Reply-To: <20200820170228.42053-1-eajames@linux.ibm.com>

From: Brad Bishop <bradleyb@fuzziesquirrel.com>

Make use of spi_max_transfer_size to avoid requesting transfers that are
too large for some spi controllers.

Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Signed-off-by: Eddie James <eajames@linux.ibm.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
 drivers/misc/eeprom/at25.c | 94 ++++++++++++++++++++++----------------
 1 file changed, 54 insertions(+), 40 deletions(-)

diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index ed8d38b09925..30f0704ab2d4 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -64,12 +64,17 @@ static int at25_ee_read(void *priv, unsigned int offset,
 {
 	struct at25_data *at25 = priv;
 	char *buf = val;
+	size_t max_chunk = spi_max_transfer_size(at25->spi);
+	size_t num_msgs = DIV_ROUND_UP(count, max_chunk);
+	size_t			nr_bytes = 0;
 	u8			command[EE_MAXADDRLEN + 1];
 	u8			*cp;
 	ssize_t			status;
 	struct spi_transfer	t[2];
 	struct spi_message	m;
 	u8			instr;
+	unsigned int		msg_offset;
+	size_t			msg_count;
 
 	if (unlikely(offset >= at25->chip.byte_len))
 		return -EINVAL;
@@ -78,57 +83,64 @@ static int at25_ee_read(void *priv, unsigned int offset,
 	if (unlikely(!count))
 		return -EINVAL;
 
-	cp = command;
-
-	instr = AT25_READ;
-	if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
-		if (offset >= (1U << (at25->addrlen * 8)))
-			instr |= AT25_INSTR_BIT3;
-	*cp++ = instr;
-
-	/* 8/16/24-bit address is written MSB first */
-	switch (at25->addrlen) {
-	default:	/* case 3 */
-		*cp++ = offset >> 16;
-		fallthrough;
-	case 2:
-		*cp++ = offset >> 8;
-		fallthrough;
-	case 1:
-	case 0:	/* can't happen: for better codegen */
-		*cp++ = offset >> 0;
-	}
+	msg_offset = (unsigned int)offset;
+	msg_count = min(count, max_chunk);
+	while (num_msgs) {
+		cp = command;
+
+		instr = AT25_READ;
+		if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+			if (msg_offset >= (1U << (at25->addrlen * 8)))
+				instr |= AT25_INSTR_BIT3;
+		*cp++ = instr;
+
+		/* 8/16/24-bit address is written MSB first */
+		switch (at25->addrlen) {
+		default:	/* case 3 */
+			*cp++ = msg_offset >> 16;
+			fallthrough;
+		case 2:
+			*cp++ = msg_offset >> 8;
+			fallthrough;
+		case 1:
+		case 0:	/* can't happen: for better codegen */
+			*cp++ = msg_offset >> 0;
+		}
 
-	spi_message_init(&m);
-	memset(t, 0, sizeof(t));
+		spi_message_init(&m);
+		memset(t, 0, sizeof(t));
 
-	t[0].tx_buf = command;
-	t[0].len = at25->addrlen + 1;
-	spi_message_add_tail(&t[0], &m);
+		t[0].tx_buf = command;
+		t[0].len = at25->addrlen + 1;
+		spi_message_add_tail(&t[0], &m);
 
-	t[1].rx_buf = buf;
-	t[1].len = count;
-	spi_message_add_tail(&t[1], &m);
+		t[1].rx_buf = buf + nr_bytes;
+		t[1].len = msg_count;
+		spi_message_add_tail(&t[1], &m);
 
-	mutex_lock(&at25->lock);
+		mutex_lock(&at25->lock);
 
-	/* Read it all at once.
-	 *
-	 * REVISIT that's potentially a problem with large chips, if
-	 * other devices on the bus need to be accessed regularly or
-	 * this chip is clocked very slowly
-	 */
-	status = spi_sync(at25->spi, &m);
-	dev_dbg(&at25->spi->dev, "read %zu bytes at %d --> %zd\n",
-		count, offset, status);
+		status = spi_sync(at25->spi, &m);
 
-	mutex_unlock(&at25->lock);
-	return status;
+		mutex_unlock(&at25->lock);
+
+		if (status)
+			return status;
+
+		--num_msgs;
+		msg_offset += msg_count;
+		nr_bytes += msg_count;
+	}
+
+	dev_dbg(&at25->spi->dev, "read %zu bytes at %d\n",
+		count, offset);
+	return 0;
 }
 
 static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
 {
 	struct at25_data *at25 = priv;
+	size_t maxsz = spi_max_transfer_size(at25->spi);
 	const char *buf = val;
 	int			status = 0;
 	unsigned		buf_size;
@@ -191,6 +203,8 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
 		segment = buf_size - (offset % buf_size);
 		if (segment > count)
 			segment = count;
+		if (segment > maxsz)
+			segment = maxsz;
 		memcpy(cp, buf, segment);
 		status = spi_write(at25->spi, bounce,
 				segment + at25->addrlen + 1);
-- 
2.26.2


  parent reply	other threads:[~2020-08-20 17:03 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-20 17:02 [PATCH 0/7] spi: Fix FSI-attached controller and AT25 drivers Eddie James
2020-08-20 17:02 ` [PATCH 1/7] spi: fsi: Handle 9 to 15 byte transfers lengths Eddie James
2020-08-20 17:02 ` [PATCH 2/7] spi: fsi: Fix clock running too fast Eddie James
2020-08-20 17:12   ` Mark Brown
2020-08-20 21:06     ` Eddie James
2020-08-25  7:10       ` Joel Stanley
2020-08-20 17:02 ` [PATCH 3/7] spi: fsi: Fix use of the bneq+ sequencer instruction Eddie James
2020-08-20 17:02 ` [PATCH 4/7] dt-bindings: fsi: fsi2spi: Document new restricted property Eddie James
2020-08-20 17:14   ` Mark Brown
2020-08-20 21:07     ` Eddie James
2020-08-21 12:03       ` Mark Brown
2020-09-08 20:44   ` Rob Herring
2020-08-20 17:02 ` [PATCH 5/7] spi: fsi: Implement restricted size for certain controllers Eddie James
2020-08-20 17:19   ` Mark Brown
2020-08-20 17:02 ` [PATCH 6/7] spi: fsi: Check mux status before transfers Eddie James
2020-08-20 17:02 ` Eddie James [this message]
2020-08-20 17:20   ` [PATCH 7/7] eeprom: at25: Split reads into chunks and cap write size Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200820170228.42053-8-eajames@linux.ibm.com \
    --to=eajames@linux.ibm.com \
    --cc=arnd@arndb.de \
    --cc=bradleyb@fuzziesquirrel.com \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=joel@jms.id.au \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.