Skip to content

Commit d005ea7

Browse files
charleskeepaxvinodkoul
authored andcommitted
soundwire: bus: Update sdw_nread/nwrite_no_pm to handle page boundaries
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> Link: https://lore.kernel.org/r/20230322164948.566962-3-ckeepax@opensource.cirrus.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent d94e1e0 commit d005ea7

1 file changed

Lines changed: 39 additions & 24 deletions

File tree

drivers/soundwire/bus.c

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -386,27 +386,46 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
386386
* Read/Write IO functions.
387387
*/
388388

389+
static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags,
390+
size_t count, u8 *val)
391+
{
392+
struct sdw_msg msg;
393+
size_t size;
394+
int ret;
395+
396+
while (count) {
397+
// Only handle bytes up to next page boundary
398+
size = min_t(size_t, count, (SDW_REGADDR + 1) - (addr & SDW_REGADDR));
399+
400+
ret = sdw_fill_msg(&msg, slave, addr, size, slave->dev_num, flags, val);
401+
if (ret < 0)
402+
return ret;
403+
404+
ret = sdw_transfer(slave->bus, &msg);
405+
if (ret < 0 && !slave->is_mockup_device)
406+
return ret;
407+
408+
addr += size;
409+
val += size;
410+
count -= size;
411+
}
412+
413+
return 0;
414+
}
415+
389416
/**
390417
* sdw_nread_no_pm() - Read "n" contiguous SDW Slave registers with no PM
391418
* @slave: SDW Slave
392419
* @addr: Register address
393420
* @count: length
394421
* @val: Buffer for values to be read
422+
*
423+
* Note that if the message crosses a page boundary each page will be
424+
* transferred under a separate invocation of the msg_lock.
395425
*/
396426
int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
397427
{
398-
struct sdw_msg msg;
399-
int ret;
400-
401-
ret = sdw_fill_msg(&msg, slave, addr, count,
402-
slave->dev_num, SDW_MSG_FLAG_READ, val);
403-
if (ret < 0)
404-
return ret;
405-
406-
ret = sdw_transfer(slave->bus, &msg);
407-
if (slave->is_mockup_device)
408-
ret = 0;
409-
return ret;
428+
return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_READ, count, val);
410429
}
411430
EXPORT_SYMBOL(sdw_nread_no_pm);
412431

@@ -416,21 +435,13 @@ EXPORT_SYMBOL(sdw_nread_no_pm);
416435
* @addr: Register address
417436
* @count: length
418437
* @val: Buffer for values to be written
438+
*
439+
* Note that if the message crosses a page boundary each page will be
440+
* transferred under a separate invocation of the msg_lock.
419441
*/
420442
int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
421443
{
422-
struct sdw_msg msg;
423-
int ret;
424-
425-
ret = sdw_fill_msg(&msg, slave, addr, count,
426-
slave->dev_num, SDW_MSG_FLAG_WRITE, (u8 *)val);
427-
if (ret < 0)
428-
return ret;
429-
430-
ret = sdw_transfer(slave->bus, &msg);
431-
if (slave->is_mockup_device)
432-
ret = 0;
433-
return ret;
444+
return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val);
434445
}
435446
EXPORT_SYMBOL(sdw_nwrite_no_pm);
436447

@@ -566,6 +577,8 @@ EXPORT_SYMBOL(sdw_update);
566577
*
567578
* This version of the function will take a PM reference to the slave
568579
* device.
580+
* Note that if the message crosses a page boundary each page will be
581+
* transferred under a separate invocation of the msg_lock.
569582
*/
570583
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
571584
{
@@ -593,6 +606,8 @@ EXPORT_SYMBOL(sdw_nread);
593606
*
594607
* This version of the function will take a PM reference to the slave
595608
* device.
609+
* Note that if the message crosses a page boundary each page will be
610+
* transferred under a separate invocation of the msg_lock.
596611
*/
597612
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
598613
{

0 commit comments

Comments
 (0)