Skip to content

Commit 9a75628

Browse files
plbossartvinodkoul
authored andcommitted
soundwire: bus: add send_async/wait APIs for BPT protocol
Add definitions and helpers for the BPT/BRA protocol. Peripheral drivers (aka ASoC codec drivers) can use this API to send bulk data such as firmware or tables. The design intent is however NOT to directly use this API but to rely on an intermediate regmap layer. The API is only available when no other audio streams have been allocated, and only one BTP/BRA stream is allowed per link. To avoid the addition of yet another lock, the refcount tests are handled in the stream master_runtime alloc/free routines where the bus_lock is already held. Another benefit of this approach is that the same bus_lock is used to handle runtime and port linked lists, which reduces the potential for misaligned configurations. In addition to exclusion with audio streams, BPT transfers have a lot of overhead, specifically registers writes are needed to enable transport in DP0. Most DMAs don't handle too well very small data sets and they may have alignment limitations. The size and alignment requirements are for now not handled by the core but must be checked by platform-specific drivers. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Tested-by: shumingf@realtek.com Link: https://lore.kernel.org/r/20250227140615.8147-8-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent b422b72 commit 9a75628

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

drivers/soundwire/bus.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,3 +2039,46 @@ void sdw_clear_slave_status(struct sdw_bus *bus, u32 request)
20392039
}
20402040
}
20412041
EXPORT_SYMBOL(sdw_clear_slave_status);
2042+
2043+
int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
2044+
{
2045+
if (msg->len > SDW_BPT_MSG_MAX_BYTES) {
2046+
dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len);
2047+
return -EINVAL;
2048+
}
2049+
2050+
/* check device is enumerated */
2051+
if (slave->dev_num == SDW_ENUM_DEV_NUM ||
2052+
slave->dev_num > SDW_MAX_DEVICES) {
2053+
dev_err(&slave->dev, "Invalid device number %d\n", slave->dev_num);
2054+
return -ENODEV;
2055+
}
2056+
2057+
/* make sure all callbacks are defined */
2058+
if (!bus->ops->bpt_send_async ||
2059+
!bus->ops->bpt_wait) {
2060+
dev_err(bus->dev, "BPT callbacks not defined\n");
2061+
return -EOPNOTSUPP;
2062+
}
2063+
2064+
return bus->ops->bpt_send_async(bus, slave, msg);
2065+
}
2066+
EXPORT_SYMBOL(sdw_bpt_send_async);
2067+
2068+
int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
2069+
{
2070+
return bus->ops->bpt_wait(bus, slave, msg);
2071+
}
2072+
EXPORT_SYMBOL(sdw_bpt_wait);
2073+
2074+
int sdw_bpt_send_sync(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
2075+
{
2076+
int ret;
2077+
2078+
ret = sdw_bpt_send_async(bus, slave, msg);
2079+
if (ret < 0)
2080+
return ret;
2081+
2082+
return sdw_bpt_wait(bus, slave, msg);
2083+
}
2084+
EXPORT_SYMBOL(sdw_bpt_send_sync);

drivers/soundwire/bus.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ struct sdw_msg {
7272
bool page;
7373
};
7474

75+
/**
76+
* struct sdw_btp_msg - Message structure
77+
* @addr: Start Register address accessed in the Slave
78+
* @len: number of bytes to transfer. More than 64Kb can be transferred
79+
* but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced.
80+
* @dev_num: Slave device number
81+
* @flags: transfer flags, indicate if xfer is read or write
82+
* @buf: message data buffer (filled by host for write, filled
83+
* by Peripheral hardware for reads)
84+
*/
85+
struct sdw_bpt_msg {
86+
u32 addr;
87+
u32 len;
88+
u8 dev_num;
89+
u8 flags;
90+
u8 *buf;
91+
};
92+
7593
#define SDW_DOUBLE_RATE_FACTOR 2
7694
#define SDW_STRM_RATE_GROUPING 1
7795

drivers/soundwire/stream.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,20 @@ static struct sdw_master_runtime
12271227
struct sdw_master_runtime *m_rt, *walk_m_rt;
12281228
struct list_head *insert_after;
12291229

1230+
if (stream->type == SDW_STREAM_BPT) {
1231+
if (bus->stream_refcount > 0 || bus->bpt_stream_refcount > 0) {
1232+
dev_err(bus->dev, "%s: %d/%d audio/BPT stream already allocated\n",
1233+
__func__, bus->stream_refcount, bus->bpt_stream_refcount);
1234+
return ERR_PTR(-EBUSY);
1235+
}
1236+
} else {
1237+
if (bus->bpt_stream_refcount > 0) {
1238+
dev_err(bus->dev, "%s: BPT stream already allocated\n",
1239+
__func__);
1240+
return ERR_PTR(-EAGAIN);
1241+
}
1242+
}
1243+
12301244
m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL);
12311245
if (!m_rt)
12321246
return NULL;
@@ -1255,6 +1269,8 @@ static struct sdw_master_runtime
12551269
m_rt->stream = stream;
12561270

12571271
bus->stream_refcount++;
1272+
if (stream->type == SDW_STREAM_BPT)
1273+
bus->bpt_stream_refcount++;
12581274

12591275
return m_rt;
12601276
}
@@ -1303,6 +1319,8 @@ static void sdw_master_rt_free(struct sdw_master_runtime *m_rt,
13031319
list_del(&m_rt->bus_node);
13041320
kfree(m_rt);
13051321

1322+
if (stream->type == SDW_STREAM_BPT)
1323+
bus->bpt_stream_refcount--;
13061324
bus->stream_refcount--;
13071325
}
13081326

@@ -2001,6 +2019,12 @@ int sdw_stream_add_master(struct sdw_bus *bus,
20012019
m_rt = sdw_master_rt_find(bus, stream);
20022020
if (!m_rt) {
20032021
m_rt = sdw_master_rt_alloc(bus, stream);
2022+
if (IS_ERR(m_rt)) {
2023+
ret = PTR_ERR(m_rt);
2024+
dev_err(bus->dev, "%s: Master runtime alloc failed for stream:%s: %d\n",
2025+
__func__, stream->name, ret);
2026+
goto unlock;
2027+
}
20042028
if (!m_rt) {
20052029
dev_err(bus->dev, "%s: Master runtime alloc failed for stream:%s\n",
20062030
__func__, stream->name);
@@ -2116,6 +2140,12 @@ int sdw_stream_add_slave(struct sdw_slave *slave,
21162140
* So, allocate m_rt and add Slave to it.
21172141
*/
21182142
m_rt = sdw_master_rt_alloc(slave->bus, stream);
2143+
if (IS_ERR(m_rt)) {
2144+
ret = PTR_ERR(m_rt);
2145+
dev_err(&slave->dev, "%s: Master runtime alloc failed for stream:%s: %d\n",
2146+
__func__, stream->name, ret);
2147+
goto unlock;
2148+
}
21192149
if (!m_rt) {
21202150
dev_err(&slave->dev, "%s: Master runtime alloc failed for stream:%s\n",
21212151
__func__, stream->name);

include/linux/soundwire/sdw.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,15 @@ struct sdw_defer {
824824
struct completion complete;
825825
};
826826

827+
/*
828+
* Add a practical limit to BPT transfer sizes. BPT is typically used
829+
* to transfer firmware, and larger firmware transfers will increase
830+
* the cold latency beyond typical OS or user requirements.
831+
*/
832+
#define SDW_BPT_MSG_MAX_BYTES (1024 * 1024)
833+
834+
struct sdw_bpt_msg;
835+
827836
/**
828837
* struct sdw_master_ops - Master driver ops
829838
* @read_prop: Read Master properties
@@ -839,6 +848,10 @@ struct sdw_defer {
839848
* @get_device_num: Callback for vendor-specific device_number allocation
840849
* @put_device_num: Callback for vendor-specific device_number release
841850
* @new_peripheral_assigned: Callback to handle enumeration of new peripheral.
851+
* @bpt_send_async: reserve resources for BPT stream and send message
852+
* using BTP protocol
853+
* @bpt_wait: wait for message completion using BTP protocol
854+
* and release resources
842855
*/
843856
struct sdw_master_ops {
844857
int (*read_prop)(struct sdw_bus *bus);
@@ -855,6 +868,9 @@ struct sdw_master_ops {
855868
void (*new_peripheral_assigned)(struct sdw_bus *bus,
856869
struct sdw_slave *slave,
857870
int dev_num);
871+
int (*bpt_send_async)(struct sdw_bus *bus, struct sdw_slave *slave,
872+
struct sdw_bpt_msg *msg);
873+
int (*bpt_wait)(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
858874
};
859875

860876
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
@@ -961,6 +977,8 @@ struct sdw_stream_runtime {
961977
* @defer_msg: Defer message
962978
* @params: Current bus parameters
963979
* @stream_refcount: number of streams currently using this bus
980+
* @btp_stream_refcount: number of BTP streams currently using this bus (should
981+
* be zero or one, multiple streams per link is not supported).
964982
* @ops: Master callback ops
965983
* @port_ops: Master port callback ops
966984
* @prop: Master properties
@@ -998,6 +1016,7 @@ struct sdw_bus {
9981016
struct sdw_defer defer_msg;
9991017
struct sdw_bus_params params;
10001018
int stream_refcount;
1019+
int bpt_stream_refcount;
10011020
const struct sdw_master_ops *ops;
10021021
const struct sdw_master_port_ops *port_ops;
10031022
struct sdw_master_prop prop;
@@ -1045,6 +1064,10 @@ int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
10451064
void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);
10461065
bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave);
10471066

1067+
int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
1068+
int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
1069+
int sdw_bpt_send_sync(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
1070+
10481071
#if IS_ENABLED(CONFIG_SOUNDWIRE)
10491072

10501073
int sdw_stream_add_slave(struct sdw_slave *slave,

0 commit comments

Comments
 (0)