diff --git a/sys/dev/sound/pci/hda/hdaa.c b/sys/dev/sound/pci/hda/hdaa.c --- a/sys/dev/sound/pci/hda/hdaa.c +++ b/sys/dev/sound/pci/hda/hdaa.c @@ -6463,10 +6463,10 @@ device_printf(dev, "Reconfiguration...\n"); ); - bus_topo_lock(); + SND_LOCK(); if ((error = device_delete_children(dev)) != 0) { - bus_topo_unlock(); + SND_UNLOCK(); return (error); } hdaa_lock(devinfo); @@ -6478,7 +6478,7 @@ device_printf(dev, "Reconfiguration done\n"); ); - bus_topo_unlock(); + SND_UNLOCK(); return (0); } diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -1403,10 +1403,10 @@ return (0); } - bus_topo_lock(); + SND_LOCK(); if ((err = device_get_children(dev, &devlist, &devcount)) != 0) { - bus_topo_unlock(); + SND_UNLOCK(); return (err); } @@ -1415,7 +1415,7 @@ HDAC_PINDUMP(devlist[i]); hdac_unlock(sc); - bus_topo_unlock(); + SND_UNLOCK(); free(devlist, M_TEMP); return (0); diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -128,6 +128,7 @@ struct pcm_channel *c; int i; + SND_LOCK(); for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); @@ -146,6 +147,7 @@ PCM_RELEASE(d); PCM_UNLOCK(d); } + SND_UNLOCK(); } static int @@ -166,7 +168,7 @@ return (0); } SYSCTL_PROC(_hw_snd, OID_AUTO, vpc_0db, - CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int), sysctl_hw_snd_vpc_0db, "I", "0db relative level"); @@ -186,7 +188,7 @@ return (0); } SYSCTL_PROC(_hw_snd, OID_AUTO, vpc_reset, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, sizeof(int), + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, sizeof(int), sysctl_hw_snd_vpc_reset, "I", "reset volume on all channels"); diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -199,7 +199,7 @@ if (PCM_DETACHING(d)) goto skip; - PCM_GIANT_ENTER(d); + PCM_SND_LOCK(d); PCM_LOCK(d); PCM_WAIT(d); @@ -281,7 +281,7 @@ PCM_RELEASE(d); PCM_UNLOCK(d); - PCM_GIANT_LEAVE(d); + PCM_SND_UNLOCK(d); skip: free(priv, M_DEVBUF); priv = NULL; @@ -314,7 +314,7 @@ if (error != 0) return (error); - PCM_GIANT_ENTER(d); + PCM_SND_LOCK(d); /* Lock snddev so nobody else can monkey with it. */ PCM_LOCK(d); @@ -359,7 +359,7 @@ } if (error != 0) { PCM_UNLOCK(d); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (error); } @@ -392,7 +392,7 @@ chn_release(rdch); if (!DSP_F_DUPLEX(flags)) { PCM_RELEASE_QUICK(d); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (rderror); } rdch = NULL; @@ -429,7 +429,7 @@ chn_release(rdch); } PCM_RELEASE_QUICK(d); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (wrerror); } wrch = NULL; @@ -449,7 +449,7 @@ if (wrch == NULL && rdch == NULL) { PCM_RELEASE(d); PCM_UNLOCK(d); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); if (wrerror != 0) return (wrerror); if (rderror != 0) @@ -466,7 +466,7 @@ PCM_RELEASE(d); PCM_UNLOCK(d); - PCM_GIANT_LEAVE(d); + PCM_SND_UNLOCK(d); return (0); } @@ -488,7 +488,7 @@ if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) return (EBADF); - PCM_GIANT_ENTER(d); + PCM_SND_LOCK(d); switch (buf->uio_rw) { case UIO_READ: @@ -513,14 +513,14 @@ if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) { if (priv->rdch != NULL || priv->wrch != NULL) dsp_unlock_chans(priv, prio); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (EBADF); } if (((*ch)->flags & (CHN_F_MMAP | CHN_F_DEAD)) || (((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) { dsp_unlock_chans(priv, prio); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (EINVAL); } else if (!((*ch)->flags & CHN_F_RUNNING)) { (*ch)->flags |= CHN_F_RUNNING; @@ -540,7 +540,7 @@ dsp_unlock_chans(priv, prio); - PCM_GIANT_LEAVE(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -707,7 +707,7 @@ if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) return (EBADF); - PCM_GIANT_ENTER(d); + PCM_SND_LOCK(d); arg_i = (int *)arg; ret = 0; @@ -717,12 +717,12 @@ if (IOCGROUP(cmd) == 'M') { if (cmd == OSS_GETVERSION) { *arg_i = SOUND_VERSION; - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (0); } ret = dsp_ioctl_channel(priv, priv->volch, cmd, arg); if (ret != -1) { - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -734,7 +734,7 @@ } else ret = EBADF; - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -770,7 +770,7 @@ ret = EINVAL; } PCM_RELEASE_QUICK(d); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -783,7 +783,7 @@ rdch = NULL; if (wrch == NULL && rdch == NULL) { - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (EINVAL); } @@ -1483,7 +1483,7 @@ ret = dsp_ioctl_channel(priv, chn, xcmd, arg); if (ret != -1) { - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -1807,7 +1807,7 @@ break; } - PCM_GIANT_LEAVE(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -1828,7 +1828,7 @@ return (events & (POLLHUP | POLLPRI | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); } - PCM_GIANT_ENTER(d); + PCM_SND_LOCK(d); ret = 0; @@ -1850,7 +1850,7 @@ dsp_unlock_chans(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); - PCM_GIANT_LEAVE(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -1908,7 +1908,7 @@ if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) return (EINVAL); - PCM_GIANT_ENTER(d); + PCM_SND_LOCK(d); dsp_lock_chans(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); wrch = priv->wrch; @@ -1920,7 +1920,7 @@ (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) || (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) { dsp_unlock_chans(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); - PCM_GIANT_EXIT(d); + PCM_SND_UNLOCK(d); return (EINVAL); } @@ -1934,7 +1934,7 @@ *object = vm_pager_allocate(OBJT_DEVICE, i_dev, size, nprot, *offset, curthread->td_ucred); - PCM_GIANT_LEAVE(d); + PCM_SND_UNLOCK(d); if (*object == NULL) return (EINVAL); @@ -1959,7 +1959,7 @@ } return; found: - bus_topo_lock(); + SND_LOCK(); d = devclass_get_softc(pcm_devclass, snd_unit); /* * If we only have a single soundcard attached and we detach it right @@ -1971,7 +1971,7 @@ *dev = d->dsp_dev; dev_ref(*dev); } - bus_topo_unlock(); + SND_UNLOCK(); } static void @@ -2068,6 +2068,7 @@ if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw) return (EINVAL); + SND_LOCK(); for (unit = 0; pcm_devclass != NULL && unit < devclass_get_maxunit(pcm_devclass); unit++) { d = devclass_get_softc(pcm_devclass, unit); @@ -2075,6 +2076,7 @@ if ((ai->dev == -1 && unit == snd_unit) || ai->dev == unit) { dsp_oss_audioinfo_unavail(ai, unit); + SND_UNLOCK(); return (0); } else { d = NULL; @@ -2093,6 +2095,7 @@ d = NULL; } } + SND_UNLOCK(); /* Exhausted the search -- nothing is locked, so return. */ if (d == NULL) @@ -2252,6 +2255,7 @@ * Search for the requested audio device (channel). Start by * iterating over pcm devices. */ + SND_LOCK(); for (unit = 0; pcm_devclass != NULL && unit < devclass_get_maxunit(pcm_devclass); unit++) { d = devclass_get_softc(pcm_devclass, unit); @@ -2406,9 +2410,12 @@ PCM_UNLOCK(d); - if (devname != NULL) + if (devname != NULL) { + SND_UNLOCK(); return (0); + } } + SND_UNLOCK(); /* Exhausted the search -- nothing is locked, so return. */ return (EINVAL); diff --git a/sys/dev/sound/pcm/feeder_rate.c b/sys/dev/sound/pcm/feeder_rate.c --- a/sys/dev/sound/pcm/feeder_rate.c +++ b/sys/dev/sound/pcm/feeder_rate.c @@ -258,6 +258,7 @@ * set resampler quality if and only if it is exist as * part of feeder chains and the channel is idle. */ + SND_LOCK(); for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); @@ -280,10 +281,12 @@ PCM_UNLOCK(d); } + SND_UNLOCK(); + return (0); } SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_quality, - CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int), sysctl_hw_snd_feeder_rate_quality, "I", "sample rate converter quality ("__XSTRING(Z_QUALITY_MIN)"=low .. " __XSTRING(Z_QUALITY_MAX)"=high)"); diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -1212,7 +1212,7 @@ if (!PCM_REGISTERED(d) || PCM_DETACHING(d)) return (EBADF); - PCM_GIANT_ENTER(d); + PCM_SND_LOCK(d); PCM_ACQUIRE_QUICK(d); ret = -1; @@ -1226,7 +1226,7 @@ MIXER_CMD_CDEV); PCM_RELEASE_QUICK(d); - PCM_GIANT_LEAVE(d); + PCM_SND_UNLOCK(d); return (ret); } @@ -1362,14 +1362,14 @@ if (*dev != NULL) return; if (strcmp(name, "mixer") == 0) { - bus_topo_lock(); + SND_LOCK(); d = devclass_get_softc(pcm_devclass, snd_unit); /* See related comment in dsp_clone(). */ if (d != NULL && PCM_REGISTERED(d) && d->mixer_dev != NULL) { *dev = d->mixer_dev; dev_ref(*dev); } - bus_topo_unlock(); + SND_UNLOCK(); } } @@ -1444,12 +1444,14 @@ * There's a 1:1 relationship between mixers and PCM devices, so * begin by iterating over PCM devices and search for our mixer. */ + SND_LOCK(); for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); if (!PCM_REGISTERED(d) || PCM_DETACHING(d)) { if ((mi->dev == -1 && i == snd_unit) || mi->dev == i) { mixer_oss_mixerinfo_unavail(mi, i); + SND_UNLOCK(); return (0); } else continue; @@ -1470,6 +1472,7 @@ if (d->mixer_dev->si_drv1 == NULL) { mixer_oss_mixerinfo_unavail(mi, i); PCM_UNLOCK(d); + SND_UNLOCK(); return (0); } @@ -1550,8 +1553,10 @@ PCM_UNLOCK(d); + SND_UNLOCK(); return (0); } + SND_UNLOCK(); return (EINVAL); } diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -71,6 +71,7 @@ #include #include #include +#include #ifndef KOBJMETHOD_END #define KOBJMETHOD_END { NULL, NULL } @@ -237,6 +238,7 @@ #define DSP_DEFAULT_SPEED 8000 +extern struct sx snd_sx; extern int pcm_veto_load; extern int snd_unit; extern int snd_verbose; @@ -334,6 +336,9 @@ void sound_oss_sysinfo(oss_sysinfo *); int sound_oss_card_info(oss_card_info *); +#define SND_LOCK() sx_xlock(&snd_sx) +#define SND_UNLOCK() sx_xunlock(&snd_sx) + #define PCM_MODE_MIXER 0x01 #define PCM_MODE_PLAY 0x02 #define PCM_MODE_REC 0x04 @@ -345,6 +350,16 @@ #define PCM_LOCKASSERT(d) mtx_assert((d)->lock, MA_OWNED) #define PCM_UNLOCKASSERT(d) mtx_assert((d)->lock, MA_NOTOWNED) +#define PCM_SND_LOCK(x) do { \ + if (((x)->flags & SD_F_MPSAFE) == 0 && !sx_xlocked(&snd_sx)) \ + SND_LOCK(); \ +} while (0) + +#define PCM_SND_UNLOCK(x) do { \ + if (((x)->flags & SD_F_MPSAFE) == 0) \ + SND_UNLOCK(); \ +} while (0) + /* * For PCM_[WAIT | ACQUIRE | RELEASE], be sure to surround these * with PCM_LOCK/UNLOCK() sequence, or I'll come to gnaw upon you! @@ -418,46 +433,6 @@ panic("%s(%d): [PCM BUSYASSERT] " \ "Failed, snddev_info=%p", __func__, __LINE__, x); \ } while (0) - -#define PCM_GIANT_ENTER(x) do { \ - int _pcm_giant = 0; \ - if (PCM_LOCKOWNED(x)) \ - panic("%s(%d): [GIANT ENTER] PCM lock owned!", \ - __func__, __LINE__); \ - if (mtx_owned(&Giant) != 0 && snd_verbose > 3) \ - device_printf((x)->dev, \ - "%s(%d): [GIANT ENTER] Giant owned!\n", \ - __func__, __LINE__); \ - if (!((x)->flags & SD_F_MPSAFE) && mtx_owned(&Giant) == 0) \ - do { \ - mtx_lock(&Giant); \ - _pcm_giant = 1; \ - } while (0) - -#define PCM_GIANT_EXIT(x) do { \ - if (PCM_LOCKOWNED(x)) \ - panic("%s(%d): [GIANT EXIT] PCM lock owned!", \ - __func__, __LINE__); \ - if (!(_pcm_giant == 0 || _pcm_giant == 1)) \ - panic("%s(%d): [GIANT EXIT] _pcm_giant screwed!", \ - __func__, __LINE__); \ - if ((x)->flags & SD_F_MPSAFE) { \ - if (_pcm_giant == 1) \ - panic("%s(%d): [GIANT EXIT] MPSAFE Giant?", \ - __func__, __LINE__); \ - if (mtx_owned(&Giant) != 0 && snd_verbose > 3) \ - device_printf((x)->dev, \ - "%s(%d): [GIANT EXIT] Giant owned!\n", \ - __func__, __LINE__); \ - } \ - if (_pcm_giant != 0) { \ - if (mtx_owned(&Giant) == 0) \ - panic("%s(%d): [GIANT EXIT] Giant not owned!", \ - __func__, __LINE__); \ - _pcm_giant = 0; \ - mtx_unlock(&Giant); \ - } \ -} while (0) #else /* !SND_DIAGNOSTIC */ #define PCM_WAIT(x) do { \ PCM_LOCKASSERT(x); \ @@ -504,37 +479,8 @@ ("%s(%d): [PCM BUSYASSERT] " \ "Failed, snddev_info=%p", \ __func__, __LINE__, x)) - -#define PCM_GIANT_ENTER(x) do { \ - int _pcm_giant = 0; \ - PCM_UNLOCKASSERT(x); \ - if (!((x)->flags & SD_F_MPSAFE) && mtx_owned(&Giant) == 0) \ - do { \ - mtx_lock(&Giant); \ - _pcm_giant = 1; \ - } while (0) - -#define PCM_GIANT_EXIT(x) do { \ - PCM_UNLOCKASSERT(x); \ - KASSERT(_pcm_giant == 0 || _pcm_giant == 1, \ - ("%s(%d): [GIANT EXIT] _pcm_giant screwed!", \ - __func__, __LINE__)); \ - KASSERT(!((x)->flags & SD_F_MPSAFE) || \ - (((x)->flags & SD_F_MPSAFE) && _pcm_giant == 0), \ - ("%s(%d): [GIANT EXIT] MPSAFE Giant?", \ - __func__, __LINE__)); \ - if (_pcm_giant != 0) { \ - mtx_assert(&Giant, MA_OWNED); \ - _pcm_giant = 0; \ - mtx_unlock(&Giant); \ - } \ -} while (0) #endif /* SND_DIAGNOSTIC */ -#define PCM_GIANT_LEAVE(x) \ - PCM_GIANT_EXIT(x); \ -} while (0) - #endif /* _KERNEL */ #endif /* _OS_H_ */ diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -52,6 +52,9 @@ int snd_unit = -1; +struct sx snd_sx; +SX_SYSINIT(snd_sx, &snd_sx, "snd sx"); + static int snd_unit_auto = -1; SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RWTUN, &snd_unit_auto, 0, "assign default unit to a newly attached device"); @@ -177,14 +180,16 @@ d = devclass_get_softc(pcm_devclass, unit); if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) return EINVAL; + SND_LOCK(); snd_unit = unit; snd_unit_auto = 0; + SND_UNLOCK(); } return (error); } /* XXX: do we need a way to let the user change the default unit? */ SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, - CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_NEEDGIANT, 0, + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, 0, sizeof(int), sysctl_hw_snd_default_unit, "I", "default sound device"); @@ -333,6 +338,7 @@ best = -1; bestprio = -100; + SND_LOCK(); for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); @@ -348,6 +354,8 @@ bestprio = prio; } } + SND_UNLOCK(); + return (best); } @@ -721,6 +729,7 @@ j = 0; + SND_LOCK(); for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); @@ -747,6 +756,7 @@ PCM_UNLOCK(d); } + SND_UNLOCK(); si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ /** @@ -767,9 +777,11 @@ * break if they try to loop through all mixers and some of them are * not available. */ + SND_LOCK(); si->nummixers = devclass_get_maxunit(pcm_devclass); si->numcards = devclass_get_maxunit(pcm_devclass); si->numaudios = devclass_get_maxunit(pcm_devclass); + SND_UNLOCK(); /* OSSv4 docs: Intended only for test apps; API doesn't really have much of a concept of cards. Shouldn't be used by applications. */ @@ -795,6 +807,7 @@ struct snddev_info *d; int i; + SND_LOCK(); for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); @@ -822,8 +835,11 @@ PCM_UNLOCK(d); } + SND_UNLOCK(); return (0); } + SND_UNLOCK(); + return (ENXIO); } diff --git a/sys/dev/sound/pcm/vchan.c b/sys/dev/sound/pcm/vchan.c --- a/sys/dev/sound/pcm/vchan.c +++ b/sys/dev/sound/pcm/vchan.c @@ -1065,6 +1065,7 @@ if (v > SND_MAXVCHANS) v = SND_MAXVCHANS; snd_maxautovchans = v; + SND_LOCK(); for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); @@ -1074,11 +1075,12 @@ vchan_setmaxauto(d, v); PCM_RELEASE_QUICK(d); } + SND_UNLOCK(); } return (error); } SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, - CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", "maximum virtual channel"); void