Repository navigation
soundwire hardening - #1665
soundwire hardening#1665plbossart wants to merge 175 commits into
Conversation
Add clearer references to sdw_slave_driver for internal macros No change for sdw_driver and module_sdw_driver to avoid compatibility issues with existing codec devices No functionality change. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Since we want to introduce master devices, rename macro so that we have consistency between slave and master device access. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Align with previous renames and shorten macro No functionality change Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Before we add master driver support, make sure there is no ambiguity and no occurrences of sdw_drv_ functions. No functionality change. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
There are too many fields called 'res' so add prefix to make it easier to track what the structures are. Pure rename, no functionality change Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
In the existing SoundWire code, the bus does not have any explicit representation for Master Devices - only SoundWire Slaves are exposed. In SoundWire, the Master Device provides the clock, synchronization information and command/control channels. When multiple links are supported, a Controller may expose more than one Master Device; they are typically embedded inside a larger audio cluster (be it in an SOC/chipset or an external audio codec), and we need to describe it using the Linux device and driver model. This will allow for configuration functions to account for external dependencies such as power rails, clock sources or wake-up mechanisms. This transition will also allow for better sysfs support without the reference count issues mentioned in the initial reviews. In this patch, we first convert the existing code to use an explicit sdw_slave_type and add error checks if this type is not set. In follow-up patches we can add support for the sdw_master_type. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Currently the .uevent callback is set at the bus level. This is not necessary, we only really need to deal with uevents for the Slave device, so move the uevent handling at that level. Suggested-by: Vinod Koul <vkoul@kernel.org> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Since we want an explicit support for the SoundWire Master device, add the definitions, following the Greybus example of a 'Host Device'. A parent (such as the Intel audio controller) would use sdw_md_add() to create the device, passing a driver as a parameter. The sdw_md_release() would be called when put_device() is invoked by the parent. We use the shortcut 'md' for 'master device' to avoid very long function names. The 'Master Device' driver exposes interfaces for probe/startup/shutdown/remove and a placeholder for autonomous clock stop support (when the bus control is handed over to a lower-power solution, typically in D0ix modes). Module namespace support is added in a separate patch. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
…stead Use sdw_master_device and driver instead of platform devices To quote GregKH: "Don't mess with a platform device unless you really have no other possible choice. And even then, don't do it and try to do something else. Platform devices are really abused, don't perpetuate it " In addition, rather than a plain-vanilla init/exit, this patch provides 3 steps in the initialization (ACPI scan, probe, startup) which makes it easier to verify hardware support for SoundWire, allocate required resources as early as possible, and conversely help make the startup() callback lighter-weight with only hardware register setup. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
While we don't have a matching function, setting an device driver is still necessary for ASoC to register DAI components as well as power management. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
The existing code does not expose a prepare operation, which is very much needed to deal with underflow and resume operations. Signed-off-by: Rander Wang <rander.wang@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
The existing code does not expose a trigger callback, which is very much required for streaming. The SoundWire stream is enabled and disabled in trigger function. Signed-off-by: Rander Wang <rander.wang@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
The sdw stream is allocated and stored in dai to share the sdw runtime information. Signed-off-by: Rander Wang <rander.wang@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Make sure all calls to the SoundWire stream API are done and involve callback Signed-off-by: Rander Wang <rander.wang@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
This function is required to enable all interrupts across all links. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Make sure all symbols in this soundwire-intel-init module are exported with a namespace. The MODULE_IMPORT_NS will be used in Intel/SOF HDaudio modules to be posted in a separate series. Namespaces are only introduced for the Intel parts of the SoundWire code at this time, in future patches we should also add namespaces for Cadence parts and the SoundWire core. Suggested-by: Greg KH <gregkh@linuxfoundation.org> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
The soundwire-intel module exports an 'intel_sdw_driver' structure, which is declared with a namespace explicitly imported by the soundwire-intel-init module. The use of namespaces might be deemed overkill here, but it did help enforce a proper code partitioning for follow-up patches on clock-stop support. Suggested-by: Greg KH <gregkh@linuxfoundation.org> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
The existing code uses one pair of interrupt handler/thread per link but at the hardware level the interrupt is shared. This works fine for legacy PCI interrupts, but leads to timeouts in MSI (Message-Signaled Interrupt) mode, likely due to edges being lost. This patch unifies interrupt handling for all links. The dedicated handler is removed since we use a common one for all shared interrupt sources, and the thread function takes care of dealing with interrupt sources. This partition follows the model used for the SOF IPC on HDaudio platforms, where similar timeout issues were noticed and doing all the interrupt handling/clearing in the thread improved reliability/stability. Validation results with 4 links active in parallel show a night-and-day improvement with no timeouts noticed even during stress tests. Latency and quality of service are not affected by the change - mostly because events on a SoundWire link are throttled by the bus frame rate (typically 8..48kHz). Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
The driver probe takes care of basic initialization and is invoked when a Slave becomes attached, after a match between the Slave DevID registers and ACPI/DT entries. The update_status callback is invoked when a Slave state changes, e.g. when it is assigned a non-zero Device Number and it reports with an ATTACHED/ALERT state. The state change detection is usually hardware-based and based on the SoundWire frame rate (e.g. double-digit microseconds) while the probe is a pure software operation, which may involve a kernel module load. In corner cases, it's possible that the state changes before the probe completes. This patch suggests the use of wait_for_completion to avoid races on startup, so that the update_status callback does not rely on invalid pointers/data structures. Signed-off-by: Rander Wang <rander.wang@intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Add support for pm_runtime with the appropriate error checks for sdw_write/read functions, e.g. when pm_runtime is not supported. Also expose internal functions without pm_runtime support, which are required to perform any sort of suspend/resume operation, as well as any enumeration tasks. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
While handling the Device0, we can safely use sdw_write_no_pm. This move will also helps us track that all other usages of sdw_write() happen when the Slave is already enumerated. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
These routines are required for power management Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Implement suspend/resume capabilities (not runtime_pm for now) The resume part is essentially a full-blown re-enumeration. When S0ix is supported, we will select clock stop mode when the ACPI target state is S0, and tear down the link for S3. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Add basic hooks in DAI .startup and .shutdown callbacks. The SoundWire IP should be powered between those two calls. The power dependencies between SoundWire and DSP are handled with the parent/child relationship, before the SoundWire master device becomes active the parent device will become active and power-up the shared rails. For now the strategy is to rely on complete enumeration when the device becomes active, so the code is a copy/paste of the sequence for system suspend/resume. In future patches, the strategy will optionally be to rely on clock stop if the enumeration time is prohibitive or when the devices connected to a link can signal a wake. A module parameter is added to make integration of new Slave devices easier, to e.g. keep the device active or prevent clock-stop. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
The system resume does the entire bus re-initialization and brings it to full-power. If the device was pm_runtime suspended, there is no need to run the pm_runtime resume sequence after the system runtime. Follow the documentation from runtime_pm.rst, and conditionally disable, set_active and re-enable the device on system resume. Note that pm_runtime_suspended() is used instead of pm_runtime_status_suspended() so that we can deal with the case where pm_runtime is disabled. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Previous patches took care of the case where the master device is pm_runtime 'suspended' when a system suspend occurs. In the case where the master device was not suspended, e.g. if suspend occurred while streaming audio, Intel validation noticed a race condition the enumeration started by the system resume may race with pm_runtime suspend. This can be simply fixed by updating the status before exiting system resume. GitHub issue: thesofproject#1482 Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
When resuming, we need to re-enumerate and restart from UNATTACHED. This will help implement a more robust state machine avoiding race conditions on resume. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
This helps make sure they are all UNATTACHED and reset the state machines. At the moment we perform a bus reset both for resume and pm_resume, this will be modified when clock-stop mode is supported Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Before checking for the presence of Device0, we first need to clean-up the internal state of Slaves that are no longer attached. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
This patch adds the signaling needed for Slave drivers to wait until the enumeration completes so that race conditions when issuing read/write commands are avoided. The calls for wait_for_completion() will be added in codec drivers in follow-up patches. The order between init_completion() and complete() is deterministic, the Slave is marked as UNATTACHED either during a Master-initiated HardReset, or when the hardware detects the Slave no longer reports as ATTACHED. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
if a slave has been attached to a bus, the slave->dev_num_sticky should be non-zero, so we can check this value to skip the ghost devices defined in ACPI table but not populated in hardware. Signed-off-by: Rander Wang <rander.wang@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
…ation Follow upstream move and convert to .dlc = COMP_CODEC_CONF Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
…ntegration/soundwire-latest Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
…egration/soundwire-latest Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
…o integration/soundwire-latest Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
…rs' into integration/soundwire-latest Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
…into integration/soundwire-latest Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
If somehow we read the interrupt status while the IP is not powered the result is probably undefined or 0xffffffff. We do know that some of the bits are reserved and read as zero, so use as a filter to discard invalid configurations. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
This function is broken due to race conditions and bad ideas... When a bus reset occurs, the clock stop is no longer prepared. FIXME: the clock stop mode1 needs to wait for the device to re-enumerate. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
This leads to a "Failed to set sync period" error log, but the values don't need to be reprogrammed. FIXME: is this the right fix? Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
| clock_stop_quirks = sdw->link_res->clock_stop_quirks; | ||
|
|
||
| if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { | ||
|
|
There was a problem hiding this comment.
nitpick: I wouldn't add empty lines at the beginning of if () {} and similar blocks - in this and following commits.
There was a problem hiding this comment.
I leave this as a degree of freedom, others use empty lines for for loops as well, it's just easier to identify the body and compare different cases.
|
|
||
| list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { | ||
|
|
||
| if (!prepare && |
There was a problem hiding this comment.
nitpick: this could do with a comment explaining the state check.
There was a problem hiding this comment.
yes, we need to explain this better, will fix.
|
Thanks @YvonneYang2 and @RanderWang, looks like we killed 3 nasty bugs with this PR. Will update and merge. Good progress! |
…n prepared
In multi-pipelines test case, there are two pipelines for playback and
capture on the same bus. The test fails with an error when setting
port params:.
[ 599.224812] rt711 sdw:0:25d:711:0: invalid dpn_prop direction 1 port_num 0
[ 599.224815] sdw_program_slave_port_params failed -22
[ 599.224819] intel-sdw sdw-master-0: Program transport params failed: -22
[ 599.224822] intel-sdw sdw-master-0: Program params failed: -22
[ 599.224828] sdw_enable_stream: SDW0 Pin2-Playback: done
This problem is root-caused to an invalid state for the stream, the
calling sequence is:
(1) hw_params for playback. The playback stream provide the port
information to Bus.
(2) stream_prepare for playback, Transport and port parameters
are computed for playback.
(3) hw_params for capture. The capture stream provide the port
information to Bus, but it has not been prepared so is not
accounted for in the bandwidth allocation.
(4) stream_enable for playback. Program transport and port parameters
for all masters and slaves. Since the transport and port parameters
are not computed for capture stream, sdw_program_slave_port_params
will generate a error when setting port params for capture.
in step (4), we should only program the ports for the stream that have
been prepared. A stream that is only in CONFIGURED state should be
ignored, its ports will be programmed when it becomes PREPARED.
Tested on Comet Lake.
GitHub issue: thesofproject#1637
Signed-off-by: Rander Wang <rander.wang@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
59a15b3 to
0971aff
Compare
63cf784 to
07348fa
Compare
|
patches applied on integration/soundwire-intel and merged on integration/soundwire-latest. That should take care of all the complicated bugs, until new ones are found of course |
Following deadlock can be triggered easily by lockdep: WARNING: possible circular locking dependency detected 6.17.0-rc3-00124-ga12c2658ced0 thesofproject#1665 Not tainted ------------------------------------------------------ check/1334 is trying to acquire lock: ff1100011d9d0678 (&q->sysfs_lock){+.+.}-{4:4}, at: blk_unregister_queue+0x53/0x180 but task is already holding lock: ff1100011d9d00e0 (&q->q_usage_counter(queue)thesofproject#3){++++}-{0:0}, at: del_gendisk+0xba/0x110 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> thesofproject#2 (&q->q_usage_counter(queue)thesofproject#3){++++}-{0:0}: blk_queue_enter+0x40b/0x470 blkg_conf_prep+0x7b/0x3c0 tg_set_limit+0x10a/0x3e0 cgroup_file_write+0xc6/0x420 kernfs_fop_write_iter+0x189/0x280 vfs_write+0x256/0x490 ksys_write+0x83/0x190 __x64_sys_write+0x21/0x30 x64_sys_call+0x4608/0x4630 do_syscall_64+0xdb/0x6b0 entry_SYSCALL_64_after_hwframe+0x76/0x7e -> thesofproject#1 (&q->rq_qos_mutex){+.+.}-{4:4}: __mutex_lock+0xd8/0xf50 mutex_lock_nested+0x2b/0x40 wbt_init+0x17e/0x280 wbt_enable_default+0xe9/0x140 blk_register_queue+0x1da/0x2e0 __add_disk+0x38c/0x5d0 add_disk_fwnode+0x89/0x250 device_add_disk+0x18/0x30 virtblk_probe+0x13a3/0x1800 virtio_dev_probe+0x389/0x610 really_probe+0x136/0x620 __driver_probe_device+0xb3/0x230 driver_probe_device+0x2f/0xe0 __driver_attach+0x158/0x250 bus_for_each_dev+0xa9/0x130 driver_attach+0x26/0x40 bus_add_driver+0x178/0x3d0 driver_register+0x7d/0x1c0 __register_virtio_driver+0x2c/0x60 virtio_blk_init+0x6f/0xe0 do_one_initcall+0x94/0x540 kernel_init_freeable+0x56a/0x7b0 kernel_init+0x2b/0x270 ret_from_fork+0x268/0x4c0 ret_from_fork_asm+0x1a/0x30 -> #0 (&q->sysfs_lock){+.+.}-{4:4}: __lock_acquire+0x1835/0x2940 lock_acquire+0xf9/0x450 __mutex_lock+0xd8/0xf50 mutex_lock_nested+0x2b/0x40 blk_unregister_queue+0x53/0x180 __del_gendisk+0x226/0x690 del_gendisk+0xba/0x110 sd_remove+0x49/0xb0 [sd_mod] device_remove+0x87/0xb0 device_release_driver_internal+0x11e/0x230 device_release_driver+0x1a/0x30 bus_remove_device+0x14d/0x220 device_del+0x1e1/0x5a0 __scsi_remove_device+0x1ff/0x2f0 scsi_remove_device+0x37/0x60 sdev_store_delete+0x77/0x100 dev_attr_store+0x1f/0x40 sysfs_kf_write+0x65/0x90 kernfs_fop_write_iter+0x189/0x280 vfs_write+0x256/0x490 ksys_write+0x83/0x190 __x64_sys_write+0x21/0x30 x64_sys_call+0x4608/0x4630 do_syscall_64+0xdb/0x6b0 entry_SYSCALL_64_after_hwframe+0x76/0x7e other info that might help us debug this: Chain exists of: &q->sysfs_lock --> &q->rq_qos_mutex --> &q->q_usage_counter(queue)thesofproject#3 Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&q->q_usage_counter(queue)thesofproject#3); lock(&q->rq_qos_mutex); lock(&q->q_usage_counter(queue)thesofproject#3); lock(&q->sysfs_lock); Root cause is that queue_usage_counter is grabbed with rq_qos_mutex held in blkg_conf_prep(), while queue should be freezed before rq_qos_mutex from other context. The blk_queue_enter() from blkg_conf_prep() is used to protect against policy deactivation, which is already protected with blkcg_mutex, hence convert blk_queue_enter() to blkcg_mutex to fix this problem. Meanwhile, consider that blkcg_mutex is held after queue is freezed from policy deactivation, also convert blkg_alloc() to use GFP_NOIO. Signed-off-by: Yu Kuai <yukuai3@huawei.com> Reviewed-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This is the take2 on interrupt filtering, cleaner handing of clock stop and tentative fix for multpipeline stress test.
This PR replaces #1640 and should also replace #1654
Issues to be checked: #1494 #1637 #1638 #1660