Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
101ea89
soundwire: intel: reset pm_runtime status during system resume
plbossart Oct 11, 2019
70a8c3a
soundwire: intel: fix race condition on system resume
plbossart Nov 26, 2019
9863500
soundwire: bus: add helper to reset Slave status to UNATTACHED
plbossart Sep 26, 2019
d937cb4
soundwire: intel: call helper to reset Slave states on resume
plbossart Sep 26, 2019
afe7c47
soundwire: bus: check first if Slaves become UNATTACHED
plbossart Sep 26, 2019
1f505ba
soundwire: bus: fix race condition with enumeration_complete signaling
plbossart Sep 26, 2019
ba1f9b4
soundwire: bus: fix race condition with initialization_complete signa…
plbossart Nov 4, 2019
b52cd8a
soundwire: bus: fix race condition by tracking UNATTACHED transition
plbossart Nov 8, 2019
835d0b5
soundwire: intel: disable pm_runtime when removing a master
plbossart Oct 9, 2019
9c3404f
soundwire: bus: disable pm_runtime in sdw_slave_delete
plbossart Oct 9, 2019
bc5387b
soundwire: stream: remove redundant pr_err traces
plbossart Nov 14, 2019
b6deaa7
soundwire: stream: update state machine and add state checks
plbossart Oct 12, 2019
5314b0d
soundwire: stream: only prepare stream when it is configured.
bardliao Sep 20, 2019
4f188c8
soundwire: stream: do not update parameters during DISABLED-PREPARED …
plbossart Oct 15, 2019
b529891
soundwire: intel: reinitialize IP+DSP in .prepare(), but only when re…
bardliao Oct 14, 2019
2198aae
soundwire: intel: pm_runtime idle scheduling
plbossart Oct 24, 2019
c7f7ce4
[HACK] add traces to debug aplay suspend/resume issue
plbossart Oct 12, 2019
f79b643
pm: add more traces
plbossart Nov 21, 2019
117abe5
soundwire: cadence_master: remove config update for interrupt setting
RanderWang Dec 2, 2019
3deb2e8
soundwire: intel: add mutex to prevent concurrent access to SHIM regi…
plbossart Dec 2, 2019
8397b38
ALSA: HDA: intel-dsp-config: add DMI info for Dell laptop
bardliao Nov 5, 2019
c442d42
soundwire: cadence_master: handle multiple status reports per Slave
plbossart Jun 11, 2019
af19be4
soundwire: Add generic bandwidth allocation algorithm
plbossart Apr 24, 2018
9596b65
soundwire: dynamic_allocation: set grp_ctrl_valid false
bardliao Aug 2, 2019
30bd01e
soundwire: bus: fix device number leak on errors
plbossart Jul 30, 2019
1a7a423
soundwire: intel: modify DMAT field for ALH
bardliao Aug 19, 2019
ef6ec03
soundwire: intel: fix factor of two in MCLK handling
bardliao Aug 19, 2019
2e19455
soundwire: cadence_master: log register write info
plbossart Jun 26, 2019
2f422c3
add more traces to bus code
plbossart Jun 11, 2019
7bc25bd
add traces for bus
plbossart Aug 1, 2019
59bcee2
[HACK] soundwire: add dynamic DEBUG in makefile
plbossart Sep 12, 2019
bb91221
ALSA: HDA: intel-dsp-config: add DMI info for Dell laptop
bardliao Nov 20, 2019
2b0de24
Soundwire: generic_bandwidth_allocation: don't free params if it is null
bardliao Dec 2, 2019
ff23e41
Soundwire: Use check pm runtime status with pm_runtime_suspended()
bardliao Dec 5, 2019
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
63 changes: 45 additions & 18 deletions Documentation/driver-api/soundwire/stream.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,22 +156,27 @@ Below shows the SoundWire stream states and state transition diagram. ::
+-----------+ +------------+ +----------+ +----------+
| ALLOCATED +---->| CONFIGURED +---->| PREPARED +---->| ENABLED |
| STATE | | STATE | | STATE | | STATE |
+-----------+ +------------+ +----------+ +----+-----+
^
|
|
v
+----------+ +------------+ +----+-----+
+-----------+ +------------+ +---+--+---+ +----+-----+
^ ^ ^
| | |
__| |___________ |
| | |
v | v
+----------+ +-----+------+ +-+--+-----+
| RELEASED |<----------+ DEPREPARED |<-------+ DISABLED |
| STATE | | STATE | | STATE |
+----------+ +------------+ +----------+

NOTE: State transition between prepare and deprepare is supported in Spec
but not in the software (subsystem)
NOTE: State transitions between ``SDW_STREAM_ENABLED`` and
``SDW_STREAM_DISABLED`` are only relevant when then INFO_PAUSE flag is
supported at the ALSA/ASoC level. Likewise the transition between
``SDW_DISABLED_STATE`` and ``SDW_PREPARED_STATE`` depends on the
INFO_RESUME flag.

NOTE2: Stream state transition checks need to be handled by caller
framework, for example ALSA/ASoC. No checks for stream transition exist in
SoundWire subsystem.
NOTE2: The framework implements basic state transition checks, but
does not e.g. check if a transition from DISABLED to ENABLED is valid
on a specific platform. Such tests need to be added at the ALSA/ASoC
level.

Stream State Operations
-----------------------
Expand Down Expand Up @@ -246,6 +251,9 @@ SDW_STREAM_PREPARED

Prepare state of stream. Operations performed before entering in this state:

(0) Steps 1 and 2 are omitted in the case of a resume operation,
where the bus bandwidth is known.

(1) Bus parameters such as bandwidth, frame shape, clock frequency,
are computed based on current stream as well as already active
stream(s) on Bus. Re-computation is required to accommodate current
Expand All @@ -270,13 +278,15 @@ Prepare state of stream. Operations performed before entering in this state:
After all above operations are successful, stream state is set to
``SDW_STREAM_PREPARED``.

Bus implements below API for PREPARE state which needs to be called once per
stream. From ASoC DPCM framework, this stream state is linked to
.prepare() operation.
Bus implements below API for PREPARE state which needs to be called
once per stream. From ASoC DPCM framework, this stream state is linked
to .prepare() operation. Since the .trigger() operations may not
follow the .prepare(), a direct transitions from
``SDW_STREAM_PREPARED`` to ``SDW_STREAM_DEPREPARED`` is allowed.

.. code-block:: c

int sdw_prepare_stream(struct sdw_stream_runtime * stream);
int sdw_prepare_stream(struct sdw_stream_runtime * stream, bool resume);


SDW_STREAM_ENABLED
Expand Down Expand Up @@ -332,6 +342,14 @@ Bus implements below API for DISABLED state which needs to be called once
per stream. From ASoC DPCM framework, this stream state is linked to
.trigger() stop operation.

When the INFO_PAUSE flag is supported, a direct transition to
``SDW_STREAM_ENABLED`` is allowed.

For resume operations where ASoC will use the .prepare() callback, the
stream can transition from ``SDW_STREAM_DISABLED`` to
``SDW_STREAM_PREPARED``, with all required settings restored but
without updating the bandwidth and bit allocation.

.. code-block:: c

int sdw_disable_stream(struct sdw_stream_runtime * stream);
Expand All @@ -353,9 +371,18 @@ state:
After all above operations are successful, stream state is set to
``SDW_STREAM_DEPREPARED``.

Bus implements below API for DEPREPARED state which needs to be called once
per stream. From ASoC DPCM framework, this stream state is linked to
.trigger() stop operation.
Bus implements below API for DEPREPARED state which needs to be called
once per stream. ALSA/ASoC do not have a concept of 'deprepare', and
the mapping from this stream state to ALSA/ASoC operation may be
implementation specific.

When the INFO_PAUSE flag is supported, the stream state is linked to
the .hw_free() operation - the stream is not deprepared on a
TRIGGER_STOP.

Other implementations may transition to the ``SDW_STREAM_DEPREPARED``
state on TRIGGER_STOP, should they require a transition through the
``SDW_STREAM_PREPARED`` state.

.. code-block:: c

Expand Down
4 changes: 4 additions & 0 deletions drivers/soundwire/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ config SOUNDWIRE_CADENCE
config SOUNDWIRE_INTEL
tristate "Intel SoundWire Master driver"
select SOUNDWIRE_CADENCE
select SOUNDWIRE_GENERIC_ALLOCATION
depends on ACPI && SND_SOC
help
SoundWire Intel Master driver.
If you have an Intel platform which has a SoundWire Master then
enable this config option to get the SoundWire support for that
device.

config SOUNDWIRE_GENERIC_ALLOCATION
tristate

endif
4 changes: 4 additions & 0 deletions drivers/soundwire/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
#
# Makefile for soundwire core
#
ccflags-y += -DDEBUG

#Bus Objs
soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o
obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o

soundwire-generic-allocation-objs := generic_bandwidth_allocation.o
obj-$(CONFIG_SOUNDWIRE_GENERIC_ALLOCATION) += soundwire-generic-allocation.o

ifdef CONFIG_DEBUG_FS
soundwire-bus-objs += debugfs.o
endif
Expand Down
143 changes: 126 additions & 17 deletions drivers/soundwire/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ int sdw_add_bus_master(struct sdw_bus *bus)
return -EINVAL;
}

if (!bus->compute_params) {
dev_err(bus->dev,
"Bandwidth allocation not configured, compute_parems no set\n");
return -EINVAL;
}

mutex_init(&bus->msg_lock);
mutex_init(&bus->bus_lock);
INIT_LIST_HEAD(&bus->slaves);
Expand Down Expand Up @@ -113,6 +119,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
struct sdw_slave *slave = to_sdw_slave_device(dev);
struct sdw_bus *bus = slave->bus;

pm_runtime_disable(dev);

sdw_slave_debugfs_exit(slave);

mutex_lock(&bus->bus_lock);
Expand Down Expand Up @@ -492,27 +500,42 @@ static int sdw_get_device_num(struct sdw_slave *slave)
static int sdw_assign_device_num(struct sdw_slave *slave)
{
int ret, dev_num;
bool new_device = false;

dev_dbg(slave->bus->dev, "in %s\n", __func__);


dev_dbg(slave->bus->dev, "in %s\n", __func__);

/* check first if device number is assigned, if so reuse that */
if (!slave->dev_num) {
mutex_lock(&slave->bus->bus_lock);
dev_num = sdw_get_device_num(slave);
mutex_unlock(&slave->bus->bus_lock);
if (dev_num < 0) {
dev_err(slave->bus->dev, "Get dev_num failed: %d\n",
dev_num);
return dev_num;
if (!slave->dev_num_sticky) {
mutex_lock(&slave->bus->bus_lock);
dev_num = sdw_get_device_num(slave);
mutex_unlock(&slave->bus->bus_lock);
if (dev_num < 0) {
dev_err(slave->bus->dev, "Get dev_num failed: %d\n",
dev_num);
return dev_num;
}
slave->dev_num = dev_num;
slave->dev_num_sticky = dev_num;
new_device = true;
} else {
slave->dev_num = slave->dev_num_sticky;
}
} else {
}

if (!new_device)
dev_info(slave->bus->dev,
"Slave already registered dev_num:%d\n",
"Slave already registered, reusing dev_num:%d\n",
slave->dev_num);

/* Clear the slave->dev_num to transfer message on device 0 */
dev_num = slave->dev_num;
slave->dev_num = 0;
}
/* Clear the slave->dev_num to transfer message on device 0 */
dev_num = slave->dev_num;
slave->dev_num = 0;

dev_dbg(slave->bus->dev, "in %s, writing dev_num %d\n", __func__, dev_num);
ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, dev_num);
if (ret < 0) {
dev_err(&slave->dev, "Program device_num %d failed: %d\n",
Expand All @@ -521,7 +544,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
}

/* After xfer of msg, restore dev_num */
slave->dev_num = dev_num;
slave->dev_num = slave->dev_num_sticky;

return 0;
}
Expand Down Expand Up @@ -630,13 +653,35 @@ static int sdw_program_device_num(struct sdw_bus *bus)

} while (ret == 0 && count < (SDW_MAX_DEVICES * 2));

dev_err(bus->dev, "End of %s ret %d\n", __func__, ret);

return ret;
}

static void sdw_modify_slave_status(struct sdw_slave *slave,
enum sdw_slave_status status)
{
mutex_lock(&slave->bus->bus_lock);

dev_vdbg(&slave->dev,
"%s: changing status slave %d status %d new status %d\n",
__func__, slave->dev_num, slave->status, status);

if (status == SDW_SLAVE_UNATTACHED) {
dev_dbg(&slave->dev,
"%s: initializing completion for Slave %d\n",
__func__, slave->dev_num);

init_completion(&slave->enumeration_complete);
init_completion(&slave->initialization_complete);

} else if (status == SDW_SLAVE_ATTACHED) {
dev_dbg(&slave->dev,
"%s: signaling completion for Slave %d\n",
__func__, slave->dev_num);

complete(&slave->enumeration_complete);
}
slave->status = status;
mutex_unlock(&slave->bus->bus_lock);
}
Expand Down Expand Up @@ -1032,8 +1077,29 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
{
enum sdw_slave_status prev_status;
struct sdw_slave *slave;
bool attached_initializing;
int i, ret = 0;

dev_dbg(bus->dev, "%s: start\n", __func__);

/* first check if any Slaves fell off the bus */
for (i = 1; i <= SDW_MAX_DEVICES; i++) {
mutex_lock(&bus->bus_lock);
if (test_bit(i, bus->assigned) == false) {
mutex_unlock(&bus->bus_lock);
continue;
}
mutex_unlock(&bus->bus_lock);

slave = sdw_get_slave(bus, i);
if (!slave)
continue;

if (status[i] == SDW_SLAVE_UNATTACHED &&
slave->status != SDW_SLAVE_UNATTACHED)
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
}

if (status[0] == SDW_SLAVE_ATTACHED) {
dev_dbg(bus->dev, "Slave attached, programming device number\n");
ret = sdw_program_device_num(bus);
Expand All @@ -1059,6 +1125,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
if (!slave)
continue;

attached_initializing = false;

switch (status[i]) {
case SDW_SLAVE_UNATTACHED:
if (slave->status == SDW_SLAVE_UNATTACHED)
Expand All @@ -1076,14 +1144,19 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
break;

case SDW_SLAVE_ATTACHED:
if (slave->status == SDW_SLAVE_ATTACHED)
if (slave->status == SDW_SLAVE_ATTACHED) {
dev_err(bus->dev, "Slave %d status attached, was already attached, ignoring\n", i);
break;

}
prev_status = slave->status;
sdw_modify_slave_status(slave, SDW_SLAVE_ATTACHED);

if (prev_status == SDW_SLAVE_ALERT)
if (prev_status == SDW_SLAVE_ALERT) {
dev_err(bus->dev, "Slave %d status attached, was alert, ignoring\n", i);
break;
}

attached_initializing = true;

ret = sdw_initialize_slave(slave);
if (ret)
Expand All @@ -1099,12 +1172,48 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
break;
}

dev_err(bus->dev, "Updating Slave %d status\n", i);
ret = sdw_update_slave_status(slave, status[i]);
if (ret)
dev_err(slave->bus->dev,
"Update Slave status failed:%d\n", ret);

if (attached_initializing)
complete(&slave->initialization_complete);

dev_err(bus->dev, "%s: Updating Slave %d status done\n",
__func__, i);
}

dev_dbg(bus->dev, "%s: end\n", __func__);

return ret;
}
EXPORT_SYMBOL(sdw_handle_slave_status);

void sdw_clear_slave_status(struct sdw_bus *bus, u32 request)
{
struct sdw_slave *slave;
int i;

/* Check all non-zero devices */
for (i = 1; i <= SDW_MAX_DEVICES; i++) {
mutex_lock(&bus->bus_lock);
if (test_bit(i, bus->assigned) == false) {
mutex_unlock(&bus->bus_lock);
continue;
}
mutex_unlock(&bus->bus_lock);

slave = sdw_get_slave(bus, i);
if (!slave)
continue;

if (slave->status != SDW_SLAVE_UNATTACHED)
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);

/* keep track of request, used in pm_runtime resume */
slave->unattach_request = request;
}
}
EXPORT_SYMBOL(sdw_clear_slave_status);
Loading