Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 104 additions & 6 deletions drivers/soundwire/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#include "irq.h"
#include "sysfs_local.h"

#define DEFAULT_BRA_WRITE_THRESHOLD 800
#define DEFAULT_BRA_READ_THRESHOLD 400
Comment on lines +16 to +17

static DEFINE_IDA(sdw_bus_ida);

static int sdw_get_id(struct sdw_bus *bus)
Expand Down Expand Up @@ -87,6 +90,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
lockdep_register_key(&bus->bus_lock_key);
__mutex_init(&bus->bus_lock, "bus_lock", &bus->bus_lock_key);

mutex_init(&bus->bpt_lock);

INIT_LIST_HEAD(&bus->slaves);
INIT_LIST_HEAD(&bus->m_rt_list);

Expand Down Expand Up @@ -163,6 +168,11 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
bus->params.curr_bank = SDW_BANK0;
bus->params.next_bank = SDW_BANK1;

if (!bus->bra_w_threshold)
bus->bra_w_threshold = DEFAULT_BRA_WRITE_THRESHOLD;
if (!bus->bra_r_threshold)
bus->bra_r_threshold = DEFAULT_BRA_READ_THRESHOLD;
Comment on lines +171 to +174

return 0;
}
EXPORT_SYMBOL(sdw_bus_master_add);
Expand Down Expand Up @@ -439,6 +449,46 @@ static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags,
return 0;
}

static int sdw_ntransfer_no_pm_bpt(struct sdw_slave *slave, u32 addr, u8 flags,
size_t count, u8 *val)
{
struct sdw_bpt_section sec;
struct sdw_bpt_msg msg;
size_t size;
int retry = 5;
int ret;

msg.sections = 1;
msg.dev_num = slave->dev_num;
msg.flags = flags;
msg.sec = &sec;

while (count) {
size = min_t(size_t, count, SDW_BPT_MSG_MAX_BYTES);

sec.addr = addr;
sec.len = size;
sec.buf = val;

do {
ret = sdw_bpt_send_sync(slave->bus, slave, &msg);
if (ret == -EAGAIN)
msleep(10);
retry--;
} while (ret == -EAGAIN && retry > 0);

if (ret < 0)
return ret;

addr += size;
val += size;
count -= size;
retry = 5;
}

return 0;
}

/**
* sdw_nread_no_pm() - Read "n" contiguous SDW Slave registers with no PM
* @slave: SDW Slave
Expand All @@ -447,10 +497,26 @@ static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags,
* @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.
* transferred under a separate invocation of the msg_lock if it is not
* transferred via BPT.
*/
int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
struct sdw_bus *bus = slave->bus;
int ret;

if (!bus->ops->bpt_send_async || !bus->ops->bpt_wait ||
count < bus->bra_r_threshold)
goto fallback;

ret = sdw_ntransfer_no_pm_bpt(slave, addr, SDW_MSG_FLAG_READ, count, val);
if (!ret)
return 0;
Comment thread
bardliao marked this conversation as resolved.

dev_dbg(&slave->dev,
"BPT read failed for addr %x, count %zu, ret %d fallback to normal read\n",
addr, count, ret);
fallback:
return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_READ, count, val);
Comment thread
bardliao marked this conversation as resolved.
}
EXPORT_SYMBOL(sdw_nread_no_pm);
Expand All @@ -463,10 +529,26 @@ EXPORT_SYMBOL(sdw_nread_no_pm);
* @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.
* transferred under a separate invocation of the msg_lock if it is not
* transferred via BPT.
Comment thread
bardliao marked this conversation as resolved.
*/
int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
struct sdw_bus *bus = slave->bus;
int ret;

if (!bus->ops->bpt_send_async || !bus->ops->bpt_wait ||
count < bus->bra_w_threshold)
goto fallback;

ret = sdw_ntransfer_no_pm_bpt(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val);
if (!ret)
return 0;

dev_dbg(&slave->dev,
"BPT write failed for addr %x, count %zu, ret %d fallback to normal write\n",
addr, count, ret);
fallback:
return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val);
Comment on lines +551 to 552
}
Comment on lines 535 to 553

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EXPORT_SYMBOL(sdw_nwrite_no_pm);
Expand Down Expand Up @@ -604,7 +686,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.
* transferred under a separate invocation of the msg_lock if it is not
* transferred via BPT.
*/
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
Expand Down Expand Up @@ -635,7 +718,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.
* transferred under a separate invocation of the msg_lock if it is not
* transferred via BPT.
*/
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
Expand Down Expand Up @@ -2094,6 +2178,7 @@ EXPORT_SYMBOL(sdw_clear_slave_status);
int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
{
int len = 0;
int ret;
int i;
Comment on lines 2178 to 2182

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We unlock the mutex when sdw_bpt_send_async, too. It should be fine. @ujfalusi What do you think?


for (i = 0; i < msg->sections; i++)
Expand All @@ -2118,13 +2203,26 @@ int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_
return -EOPNOTSUPP;
}

return bus->ops->bpt_send_async(bus, slave, msg);
/* Serialize BPT/BRA transfers per bus: PDIs and DMA resources are shared */
mutex_lock(&bus->bpt_lock);

ret = bus->ops->bpt_send_async(bus, slave, msg);
if (ret < 0)
mutex_unlock(&bus->bpt_lock);

/* on success the lock is held until sdw_bpt_wait() */
return ret;
}
EXPORT_SYMBOL(sdw_bpt_send_async);

int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
{
return bus->ops->bpt_wait(bus, slave, msg);
int ret;

ret = bus->ops->bpt_wait(bus, slave, msg);
mutex_unlock(&bus->bpt_lock);

return ret;
}
Comment on lines +2206 to 2226

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the previous comment

EXPORT_SYMBOL(sdw_bpt_wait);

Expand Down
7 changes: 7 additions & 0 deletions include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,10 @@ struct sdw_stream_runtime {
* are supported. This flag is populated by drivers after reading
* appropriate firmware (ACPI/DT).
* @lane_used_bandwidth: how much bandwidth in bits per second is used by each lane
* @bra_w_threshold: Message-size threshold (bytes) above which BPT write is used.
* If set to 0, a default is used.
* @bra_r_threshold: Message-size threshold (bytes) above which BPT read is used.
* If set to 0, a default is used.
Comment on lines +1031 to +1034
*/
struct sdw_bus {
struct device *dev;
Expand All @@ -1044,6 +1048,7 @@ struct sdw_bus {
int stream_refcount;
int bpt_stream_refcount;
struct sdw_stream_runtime *bpt_stream;
struct mutex bpt_lock; /* serialize BPT/BRA transfers per bus */
const struct sdw_master_ops *ops;
const struct sdw_master_port_ops *port_ops;
struct sdw_master_prop prop;
Expand All @@ -1063,6 +1068,8 @@ struct sdw_bus {
#endif
bool multi_link;
unsigned int lane_used_bandwidth[SDW_MAX_LANES];
unsigned int bra_w_threshold;
unsigned int bra_r_threshold;
Comment thread
bardliao marked this conversation as resolved.
};

struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name, enum sdw_stream_type type);
Expand Down
5 changes: 5 additions & 0 deletions sound/soc/sof/intel/hda-sdw-bpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ int hda_sdw_bpt_open(struct device *dev, int link_id, struct hdac_ext_stream **b
int ret1;
int ret;

if (!sdev->dspless_mode_selected && sdev->first_boot) {
dev_dbg(dev, "SOF FW boot not complete yet\n");
return -ENXIO;
}
Comment thread
bardliao marked this conversation as resolved.
Comment thread
bardliao marked this conversation as resolved.
Comment thread
bardliao marked this conversation as resolved.

num_channels_tx = DIV_ROUND_UP(tx_dma_bandwidth, BPT_FREQUENCY * 32);

ret = hda_sdw_bpt_dma_prepare(dev, bpt_tx_stream, dmab_tx_bdl, bpt_tx_num_bytes,
Expand Down
Loading