Commit 27b932e32fab ("sound: Safely remove channel from list in one
pass") optimized CHN_REMOVE_SAFE() to perform almost equally to
CHN_REMOVE(), so we can turn CHN_REMOVE_SAFE() into CHN_REMOVE() without
fears of performance regressions, while also being more robust.
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D48249
(cherry picked from commit ffcefe5310e084415a2f292a00f4637d4059c40f)
The CHN_REMOVE_SAFE() macro did two traversals of the channel list to
remove a channel, one to check whether the channel is an element of the
list, and a second traversal through SLIST_REMOVE(). Reduce this to one
traversal, while still preventing a NULL dereference in case the channel
in question is not present in the list.
While here, rename the macro arguments to something more descriptive.
MFC after: 1 week
Reviewed by: christos
Differential Revision: https://reviews.freebsd.org/D48207
(cherry picked from commit 27b932e32faba1137ff307d05b787d837ccadda8)
Main goal is to have a unit test, with sample test data that is verified
against the current macro implementation of pcm sample read and write
functions. With a test in place, we can proceed on a planned refactoring
of the sample read and write code, and confidently check the new code
for regressions.
Implementation of the unit test itself has to avoid any cast or
conversion affected by endianness, to make the tests compatible with all
machine architectures.
MFC after: 1 week
Reviewed by: christos, markj
Differential Revision: https://reviews.freebsd.org/D48330
(cherry picked from commit 27ef5d48c729defb83a8822143dc71ab17f9d68b)
It uses the same audio codec as 12th gen (PCI ID 0x0002).
Actually everything is the same, except the CPU.
Signed-off-by: Daniel Schaefer <dhs@frame.work>
(cherry picked from commit 48b9d78a0a9d795cfdeb56895a27309aadd50c77)
Remove uses of cv_waiters in PCM_RELEASE and CHN_BROADCAST, and also use
a counter around cv_timedwait_sig() in chn_sleep(), which is checked in
pcm_killchans(), as opposed to reading cv_waiters directly, which is a
layering violation.
While here, move CHN_BROADCAST below the channel lock operations.
Reported by: avg, jhb, markj
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, avg
Differential Revision: https://reviews.freebsd.org/D47780
(cherry picked from commit 46a97b9cd6fd4415270afe4070082ae69ee21035)
No functional change intended.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47737
(cherry picked from commit 5a217a8d7d2a0dc19eb5d7bb1bd0f21116fbcf69)
Part of a series of patches to cleanup/simplify pcm/.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D47736
(cherry picked from commit 88eaa1504d12c82a36d83c16e9fd6c41175d2e0a)
These routines are already implemented in pcm/intpcm.h.
No functional change intended.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47734
(cherry picked from commit b882251204128388eb2f8e4f74e83ff1ca7863c4)
No functional change intended.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47733
(cherry picked from commit 00731aaaed76785af8befe13e9a4e85b3554b3f5)
No functional change intended.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D47732
(cherry picked from commit 0b4e32912566d802c7a6501d9ce8119f04dbc2fb)
The KASSERT in chn_sleep() can be triggered if more than one thread
wants to sleep on a given channel at the same time. While this is not
really a common scenario, tools such as stress2, which use fork() and
the child process(es) inherit the parent's FDs as a result, we can end
up triggering such scenarios.
Fix this by removing CHN_F_SLEEPING altogether, which is not very useful
in the first place:
- CHN_BROADCAST() checks cv_waiters already, so there is no need to
check CHN_F_SLEEPING as well.
- We can check whether cv_waiters is 0 in pcm_killchans(), instead of
whether CHN_F_SLEEPING is not set.
Reported by: dougm, pho (stress2)
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47559
(cherry picked from commit 5317480967bfc8bf678e4da3fce81bcb3f5b7836)
Since SD_F_REGISTERED is cleared at the same time SD_F_DETACHING and
SD_F_DYING are set, and since PCM_DETACHING() is always used in
conjuction with PCM_REGISTERED()/DSP_REGISTERED(), it is enough to just
check SD_F_REGISTERED.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47463
(cherry picked from commit 6d4c59e26189a8c19fd0832e89f9b089330cbfcb)
This patch fixes multiple different panic scenarios occuring during
hot-unload:
1. The channel is unlocked in chn_read()/chn_write() for uiomove(9) and
in the meantime we enter pcm_killchans() and free it. By the time we
have returned from userland and try to lock it back, the channel will
have been freed.
2. The parent channel has been freed in pcm_killchans(), but at the same
time, some yet-unstopped vchan's chn_read()/chn_write() calls
chn_start(), which eventually calls vchan_trigger(), which references
the freed parent.
3. PCM_WAIT() panics because it references a freed PCM lock.
For scenarios 1 and 2, refactor pcm_killchans() to first make sure all
channels have been stopped, and then proceed to free them one by one, as
opposed to freeing the first free channel until all channels have been
freed. This change makes the code more robust, but might introduce some
performance overhead when many channels are allocated, since we
continuously loop through the channel list until all of them are
stopped, and then we loop one last time to free them.
For scenario 3, restructure the code so that we can use destroy_dev(9)
instead of destroy_dev_sched(9) in dsp_destroy_dev(). Because
destroy_dev(9) blocks until all references to the device have went away,
we ensure that the PCM cv and lock will be freed safely.
While here, move the delete_unrhdr(9) calls to pcm_killchans() and
re-order some lines.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D47462
(cherry picked from commit 2839ad58dd8a4cf5294180fc599800c437a8d4d8)
Consider the following scenario:
1. CHN currently has its trigger set to PCMTRIG_STOP.
2. Thread A locks CHN, calls CHANNEL_TRIGGER(PCMTRIG_START), sets the
trigger to PCMTRIG_START and unlocks.
3. Thread B picks up the lock, calls CHANNEL_TRIGGER(PCMTRIG_ABORT) and
returns a non-zero value, so it returns from chn_trigger() as well.
4. Thread A picks up the lock and adds CHN to the list, which is
_wrong_, because the last call to CHANNEL_TRIGGER() was with
PCMTRIG_ABORT, meaning the channel is stopped, yet we are adding it
to the list and marking it as started.
Another problematic scenario:
1. Thread A locks CHN, sets the trigger to PCMTRIG_ABORT, and unlocks
CHN. It then locks PCM and _removes_ CHN from the list.
2. In the meantime, since thread A unlocked CHN, thread B has locked it,
set the trigger to PCMTRIG_START, unlocked it, and is now blocking on
PCM held by thread A.
3. At the same time, thread C locks CHN, sets the trigger back to
PCMTRIG_ABORT, unlocks CHN, and is also blocking on PCM. However,
once thread A unlocks PCM, because thread C is higher-priority than
thread B, it picks up the PCM lock instead of thread B, and because
CHN is already removed from the list, and thread B hasn't added it
back yet, we take a page fault in CHN_REMOVE() by trying to remove a
non-existent element.
To fix the former scenario, set the channel trigger before the call to
CHANNEL_TRIGGER() (could also come after, doesn't really matter) and
check if anything changed one we lock CHN back.
To fix the latter scenario, use the SAFE variants of CHN_INSERT_HEAD()
and CHN_REMOVE(). A similar scenario can occur in vchan_trigger(), so do
the trigger setting after we've locked the parent channel.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D47461
(cherry picked from commit 5ac39263d825d7b2f8a89614a63fee90ffc77c07)
Use callout_init_mtx(9) to associate the callback with the driver's
lock. Also make sure the callout is stopped properly during detach.
While here, introduce a dummy_active() function to know when it's
appropriate to stop or not reschedule the callout.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47459
(cherry picked from commit 5bd08172b4150503c9cf60ffe3c97716c5bf6fa1)
When running FreeBSD on an arm64/aarch64 QEMU virtual machine, using the
Intel HD Audio Controller (ich6) (intel-hda), for example, and by
following the procedure in the handbook ("Setting Up the Sound Card"):
kldload snd_driver
The following error is shown:
KLD snd_driver.ko: depends on snd_cmi - not available or version mismatch
This is because the CMedia sound driver (snd_cmi) is only built for i386
and amd64.
Add the same guards to the snd_driver metadriver.
Reviewed by: christos, emaste
Approved by: emaste (mentor)
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D47399
(cherry picked from commit 0187bc8a472ef21ddb901f797d46075fc0d5eb14)
The way a sound driver currently registers to sound(4) is using the
following sequence of function calls:
1. pcm_register() to initialize snddev_info.
2. pcm_addchan() calls to create the device's primary channels.
3. pcm_setstatus() to do the final setup.
While using 3 different functions in a specific order might not be very
elegant, this pattern cannot be easily avoided. However, pcm_register()
and pcm_setstatus() are especially confusing, since one would
intuitively expect:
1. pcm_register() to actually do the registration, as opposed to a basic
initialization.
2. pcm_setstatus() to, as the name suggests, set some kind of status, as
opposed to finalizing the registration.
This patch renames pcm_register() to pcm_init(), and pcm_setstatus() to
pcm_register(). Drivers are modified accordingly.
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D47325
(cherry picked from commit 516a9c0212b003e1da0c6f4476dbe4f3f431606c)
These flags are properly set in pcm_setstatus(), once the primary
channels have been created. The existing comment already states that
this is wrong.
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47324
(cherry picked from commit 3a7d40c692622cc614a3839491c345d945f474fe)
The d->status string is populated in pcm_setstatus() anyway, so call
sndstat_register() after we populate it, and are closer to finalizing
the device creation.
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47323
(cherry picked from commit 181a31d8349088cbcead8dcbff8d62ee8af6c913)
Create the sysctl and /dev/dsp* nodes in pcm_setstatus(), which is
responsible for finalizing the device initialization, instead of doing
this in the middle of the initialization.
For the sysctl creation specifically, move them into pcm_sysinit(),
since this is where we create the rest of the sysctl nodes anyway.
A side effect of this change is, that we avoid the possibility of racing
in between pcm_register() and pcm_setstatus() by accessing /dev/dspX or
the sysctls within that window.
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47322
(cherry picked from commit 66f3eb14e955d3917f817ff346d33d839679c2cf)
pcm_veto_load is used to prevent pcm_register() from running if the root
feeder has not been registered yet. However, feeder_register_root() is a
SYSINIT.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj, emaste
Differential Revision: https://reviews.freebsd.org/D47280
(cherry picked from commit 98cd27c8e13418fa517a02844641f390f9389987)
No longer used.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D47269
(cherry picked from commit 9a6cf27583ffc13bb0a7c5be0704ba0d2f3b834d)
When adding a new vchan, we are looking for a parent channel which
either already has vchans (i.e CHN_F_HAS_VCHAN), or does not, but is
also not being used (i.e !CHN_F_BUSY). Since CHN_F_BUSY essentially
tells us if the channel is currently being used or not, there is no need
to check if the channel's refcount is 0 as well.
When removing a vchan, we first check if we have only 1 vchan allocated
that is also being used (so we cannot remove it at the moment), and then
we check if the vchan is not busy and remove it. Again, checking
CHN_F_BUSY is enough.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D47268
(cherry picked from commit 43c0b593c2c3b2c07009c031a0e7e8190a45b31a)
Before de8c0d15a64fa ("sound: Get rid of snd_clone and use
DEVFS_CDEVPRIV(9)"), sound(4) would create one device for each allocated
channel. The device names would be chosen from dsp_cdevs[], and created
with dsp_unit2name(). Additionally, dsp_cdevs[] was also used to match
these devices names, as well as OSSv4 aliases in dsp_clone().
Since sound(4) does not create separate devices for each channel
anymore, the meaning and use dsp_cdevs[] has changed. Part of it no
longer corresponds to devices at all, but instead is used to create
channel names, and another part is used to match only OSSv4 aliases in
dsp_clone().
To address this confusion, separate dsp_cdevs[] into a dsp_aliases[]
array, and move dsp_unit2name() to pcm/channel.c and rename it to
chn_mkname().
While here, get rid of the SND_DEV_DSPHW_* channel types, and simply use
the existing PCMDIR_* constants as the channel types. There is no need
to duplicate the same meaning twice.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D47199
(cherry picked from commit 802c78f5194e4524faa30ea57adbf00f28fc72c6)
(cherry picked from commit b1bb6934bb8774dd96be76d88e6824e49b613549)
Needed by a follow-up patch, so that channels can be sorted properly.
This change does not affect the behavior of any subsystem.
While here, change to an enum.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47198
(cherry picked from commit a4111e9dc7225618fa8d2af64d866cf0b0aebd56)
DSP_REGISTERED calls PCM_REGISTERED, and already contains all the checks
we are doing.
No functional change intended.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47196
(cherry picked from commit bb5e3ac1a7b71480a50fc0c813c916a3d058336c)
DSP_REGISTERED first checks if the softc is not null, through
PCM_REGISTERED, which in turn calls PCM_ALIVE, whereas PCM_DETACHING
accesses the softc flags directly.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj, emaste
Differential Revision: https://reviews.freebsd.org/D47195
(cherry picked from commit 9693241188aa6882166b091d9006f9d0affeda7e)
Both conditions are the same, so the second one is unreachable.
PR: 229550
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: andreast, markj
Differential Revision: https://reviews.freebsd.org/D47167
(cherry picked from commit 6f96ef84b359137a51dc1e717887ca7d31ba7bad)
No functional change intended.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: markj, emaste
Differential Revision: https://reviews.freebsd.org/D47152
(cherry picked from commit de009cf68ba68aa5823be3d6afeebb49a15b1251)
These malloc(9) calls are in contexts where sleeping is permitted.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, zlei, markj, emaste
Differential Revision: https://reviews.freebsd.org/D46845
(cherry picked from commit 5e33eca8e8f359d4d48f4c50334a03748420a7da)
The current channel naming convention is:
pcmX:[virtual_]play|record:dspX.[v]p|rY
- pcmX and dspX share the same unit numbers
- "[v]p|r" gives us the same information as "[virtual_]play|record"
Remove the redundant information, so that the channel names become more
readable: dspX.[virtual_]play|record.Y
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D46836
(cherry picked from commit c30f531ddb629ab51359fb540c8ef6068bab288b)
Currently we create and destroy channels with the following consistent
pattern:
- chn_init() -> pcm_chn_add()
- pcm_chn_remove() -> chn_kill()
Instead of calling two separate functions, merge pcm_chn_add() with
chn_init(), and pcm_chn_remove() with chn_kill().
Another benefit of this change is that we avoid the confusion caused by
having pcm_chn_add(), as well as pcm_addchan().
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D46835
(cherry picked from commit 9263f854e9a63cc326a3d5f6331b933c4a010abf)
feeder_rate_min functions as the lower boundary.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj, emaste
Differential Revision: https://reviews.freebsd.org/D46834
(cherry picked from commit f3092614bcae949332a8f21f7b78ba68b3ee5899)
Instead of checking the value of "ret" multiple times, just set a goto
label and jump there immediately in case of an error.
While here, remove a redundant assignment to "d".
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj, emaste
Differential Revision: https://reviews.freebsd.org/D46833
(cherry picked from commit 3cab66d12d439357b948093756ca1af87967c8cc)
No longer used.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D46522
(cherry picked from commit 248aced26eee6f569717618d097bc2205a93c800)
If we do not enter dummy_chan_trigger() before detaching, we'll get a
use-after-free since the callout(9) callback might be called after
having been detached.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj, emaste
Differential Revision: https://reviews.freebsd.org/D46715
(cherry picked from commit e42c8267821952407d4f4064026058aeaaa741ac)
feeder_register() is currently a SYSINIT in order to create the root
feeder, which happens only when feedercnt is 0. Separating the root
feeder registration makes the code more readable.
No functional change intended.
While here, fix some style errors.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, zlei, markj
Differential Revision: https://reviews.freebsd.org/D46821
(cherry picked from commit 97570db05ced435f4fb1c6a67bdb16966ce5e4d9)
There is no reason to initialize global variables in feeder_register(),
as these variables are unrelated to what the function does. Instead,
initialize them during sound(4) load.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: zlei
Differential Revision: https://reviews.freebsd.org/D46749
(cherry picked from commit 0a0301deb5b6a9c66829dd20cff9d40c5ba9ad92)
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: emaste
Differential Revision: https://reviews.freebsd.org/D46856
(cherry picked from commit 41ff4177614562923a30e2541e2a15883a4ce32c)