From: Charles Keepax <ckeepax@opensource.cirrus.com>
To: <vkoul@kernel.org>
Cc: <yung-chuan.liao@linux.intel.com>,
<pierre-louis.bossart@linux.intel.com>, <sanyog.r.kale@intel.com>,
<alsa-devel@alsa-project.org>, <linux-kernel@vger.kernel.org>,
<patches@opensource.cirrus.com>
Subject: [PATCH v2 3/3] soundwire: bus: Update sdw_nread/nwrite_no_pm to handle page boundaries
Date: Wed, 22 Mar 2023 16:49:48 +0000 [thread overview]
Message-ID: <20230322164948.566962-3-ckeepax@opensource.cirrus.com> (raw)
In-Reply-To: <20230322164948.566962-1-ckeepax@opensource.cirrus.com>
Currently issuing a sdw_nread/nwrite_no_pm across a page boundary
will silently fail to write correctly as nothing updates the page
registers, meaning the same page of the chip will get rewritten
with each successive page of data.
As the sdw_msg structure contains page information it seems
reasonable that a single sdw_msg should always be within one
page. It is also mostly simpler to handle the paging at the
bus level rather than each master having to handle it in their
xfer_msg callback.
As such add handling to the bus code to split up a transfer into
multiple sdw_msg's when they go across page boundaries.
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
Changes since v1:
- Switch from min to min_t to avoid the build issues on MIPs/i386
- Added comments to the kernel doc to say that large transactions will
be broken up.
Thanks,
Charles
drivers/soundwire/bus.c | 63 +++++++++++++++++++++++++----------------
1 file changed, 39 insertions(+), 24 deletions(-)
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index f1ffb8e0839dd..e157a39a82ce5 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -386,27 +386,46 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
* Read/Write IO functions.
*/
+static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags,
+ size_t count, u8 *val)
+{
+ struct sdw_msg msg;
+ size_t size;
+ int ret;
+
+ while (count) {
+ // Only handle bytes up to next page boundary
+ size = min_t(size_t, count, (SDW_REGADDR + 1) - (addr & SDW_REGADDR));
+
+ ret = sdw_fill_msg(&msg, slave, addr, size, slave->dev_num, flags, val);
+ if (ret < 0)
+ return ret;
+
+ ret = sdw_transfer(slave->bus, &msg);
+ if (ret < 0 && !slave->is_mockup_device)
+ return ret;
+
+ addr += size;
+ val += size;
+ count -= size;
+ }
+
+ return 0;
+}
+
/**
* sdw_nread_no_pm() - Read "n" contiguous SDW Slave registers with no PM
* @slave: SDW Slave
* @addr: Register address
* @count: length
* @val: Buffer for values to be read
+ *
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
- struct sdw_msg msg;
- int ret;
-
- ret = sdw_fill_msg(&msg, slave, addr, count,
- slave->dev_num, SDW_MSG_FLAG_READ, val);
- if (ret < 0)
- return ret;
-
- ret = sdw_transfer(slave->bus, &msg);
- if (slave->is_mockup_device)
- ret = 0;
- return ret;
+ return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_READ, count, val);
}
EXPORT_SYMBOL(sdw_nread_no_pm);
@@ -416,21 +435,13 @@ EXPORT_SYMBOL(sdw_nread_no_pm);
* @addr: Register address
* @count: length
* @val: Buffer for values to be written
+ *
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
- struct sdw_msg msg;
- int ret;
-
- ret = sdw_fill_msg(&msg, slave, addr, count,
- slave->dev_num, SDW_MSG_FLAG_WRITE, (u8 *)val);
- if (ret < 0)
- return ret;
-
- ret = sdw_transfer(slave->bus, &msg);
- if (slave->is_mockup_device)
- ret = 0;
- return ret;
+ return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val);
}
EXPORT_SYMBOL(sdw_nwrite_no_pm);
@@ -566,6 +577,8 @@ EXPORT_SYMBOL(sdw_update);
*
* This version of the function will take a PM reference to the slave
* device.
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
@@ -593,6 +606,8 @@ EXPORT_SYMBOL(sdw_nread);
*
* This version of the function will take a PM reference to the slave
* device.
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
--
2.30.2
next prev parent reply other threads:[~2023-03-22 16:50 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-22 16:49 [PATCH v2 1/3] soundwire: bus: Remove now outdated comments on no_pm IO Charles Keepax
2023-03-22 16:49 ` [PATCH v2 2/3] soundwire: bus: Update kernel doc for no_pm functions Charles Keepax
2023-03-22 16:49 ` Charles Keepax [this message]
2023-03-31 13:17 ` [PATCH v2 1/3] soundwire: bus: Remove now outdated comments on no_pm IO Vinod Koul
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=20230322164948.566962-3-ckeepax@opensource.cirrus.com \
--to=ckeepax@opensource.cirrus.com \
--cc=alsa-devel@alsa-project.org \
--cc=linux-kernel@vger.kernel.org \
--cc=patches@opensource.cirrus.com \
--cc=pierre-louis.bossart@linux.intel.com \
--cc=sanyog.r.kale@intel.com \
--cc=vkoul@kernel.org \
--cc=yung-chuan.liao@linux.intel.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox