From feb20faec73ba0b30f949d54c4153cf0ad3807c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Jun 2018 09:03:51 +0200 Subject: ALSA: hda - Move in_pm accessors to HDA core The in_pm atomic in hdac_device is an important field used as a flag as well as a refcount for PM. The existing snd_hdac_power_up/down helpers already refer to it in the HD-audio core code, while the code to actually setting the value (atomic_inc() / _dec()) is open-coded in HDA legacy side, which is hard to find. This patch adds the helper functions to set/reset the in_pm counter to HDA core and use them in HDA legacy side, for making it clearer who / where the PM is managed. There is no functional changes, just code refactoring. Reviewed-by: Chris Wilson Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'include/sound') diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index c052afc27547..294a5a21937b 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -171,12 +172,38 @@ int snd_hdac_power_down(struct hdac_device *codec); int snd_hdac_power_up_pm(struct hdac_device *codec); int snd_hdac_power_down_pm(struct hdac_device *codec); int snd_hdac_keep_power_up(struct hdac_device *codec); + +/* call this at entering into suspend/resume callbacks in codec driver */ +static inline void snd_hdac_enter_pm(struct hdac_device *codec) +{ + atomic_inc(&codec->in_pm); +} + +/* call this at leaving from suspend/resume callbacks in codec driver */ +static inline void snd_hdac_leave_pm(struct hdac_device *codec) +{ + atomic_dec(&codec->in_pm); +} + +static inline bool snd_hdac_is_in_pm(struct hdac_device *codec) +{ + return atomic_read(&codec->in_pm); +} + +static inline bool snd_hdac_is_power_on(struct hdac_device *codec) +{ + return !pm_runtime_suspended(&codec->dev); +} #else static inline int snd_hdac_power_up(struct hdac_device *codec) { return 0; } static inline int snd_hdac_power_down(struct hdac_device *codec) { return 0; } static inline int snd_hdac_power_up_pm(struct hdac_device *codec) { return 0; } static inline int snd_hdac_power_down_pm(struct hdac_device *codec) { return 0; } static inline int snd_hdac_keep_power_up(struct hdac_device *codec) { return 0; } +static inline void snd_hdac_enter_pm(struct hdac_device *codec) {} +static inline void snd_hdac_leave_pm(struct hdac_device *codec) {} +static inline bool snd_hdac_is_in_pm(struct hdac_device *codec) { return 0; } +static inline bool snd_hdac_is_power_on(struct hdac_device *codec) { return 1; } #endif /* -- cgit v1.2.3 From d64c5cf8e89d124355924c513a42b16f0d7d3a03 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 6 Jul 2018 13:50:36 +0100 Subject: ALSA: pcm: Allow drivers to set R/W wait time. Currently ALSA core blocks userspace for about 10 seconds for PCM R/W IO. This needs to be configurable for modern hardware like DSPs where no pointer update in milliseconds can indicate terminal DSP errors. Add a substream variable to set the wait time in ms. This allows userspace and drivers to recover more quickly from terminal DSP errors. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 + sound/core/pcm_lib.c | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'include/sound') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index e054c583d3b3..fcdf358a25f0 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -462,6 +462,7 @@ struct snd_pcm_substream { /* -- timer section -- */ struct snd_timer *timer; /* timer */ unsigned timer_running: 1; /* time is running */ + long wait_time; /* time in ms for R/W to wait for avail */ /* -- next substream -- */ struct snd_pcm_substream *next; /* -- linked substreams -- */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index c1d2e8e1fc6b..5736860f325b 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1833,12 +1833,19 @@ static int wait_for_avail(struct snd_pcm_substream *substream, if (runtime->no_period_wakeup) wait_time = MAX_SCHEDULE_TIMEOUT; else { - wait_time = 10; - if (runtime->rate) { - long t = runtime->period_size * 2 / runtime->rate; - wait_time = max(t, wait_time); + /* use wait time from substream if available */ + if (substream->wait_time) { + wait_time = substream->wait_time; + } else { + wait_time = 10; + + if (runtime->rate) { + long t = runtime->period_size * 2 / + runtime->rate; + wait_time = max(t, wait_time); + } + wait_time = msecs_to_jiffies(wait_time * 1000); } - wait_time = msecs_to_jiffies(wait_time * 1000); } for (;;) { -- cgit v1.2.3 From fa84cf094ef9667e2b91c104b0a788fd1896f482 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Jul 2018 07:40:53 +0200 Subject: ALSA: pcm: Nuke snd_pcm_lib_mmap_vmalloc() snd_pcm_lib_mmap_vmalloc() was supposed to be implemented with somewhat special for vmalloc handling, but in the end, this turned to just the default handler, i.e. NULL. As the situation has never changed over decades, let's rip it off. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- drivers/staging/most/sound/sound.c | 1 - include/sound/pcm.h | 2 -- sound/drivers/aloop.c | 1 - sound/drivers/vx/vx_pcm.c | 2 -- sound/firewire/bebob/bebob_pcm.c | 1 - sound/firewire/dice/dice-pcm.c | 2 -- sound/firewire/digi00x/digi00x-pcm.c | 1 - sound/firewire/fireface/ff-pcm.c | 1 - sound/firewire/fireworks/fireworks_pcm.c | 1 - sound/firewire/isight.c | 1 - sound/firewire/motu/motu-pcm.c | 2 -- sound/firewire/oxfw/oxfw-pcm.c | 2 -- sound/firewire/tascam/tascam-pcm.c | 1 - sound/mips/sgio2audio.c | 3 --- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 1 - sound/soc/codecs/rt5514-spi.c | 1 - sound/usb/6fire/pcm.c | 1 - sound/usb/caiaq/audio.c | 1 - sound/usb/hiface/pcm.c | 1 - sound/usb/misc/ua101.c | 2 -- sound/usb/pcm.c | 2 -- 21 files changed, 30 deletions(-) (limited to 'include/sound') diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c index 04c18323c2ea..89b02fc305b8 100644 --- a/drivers/staging/most/sound/sound.c +++ b/drivers/staging/most/sound/sound.c @@ -457,7 +457,6 @@ static const struct snd_pcm_ops pcm_ops = { .trigger = pcm_trigger, .pointer = pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static int split_arg_list(char *buf, char **card_name, u16 *ch_num, diff --git a/include/sound/pcm.h b/include/sound/pcm.h index fcdf358a25f0..1206045ccf03 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1342,8 +1342,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s #define snd_pcm_lib_mmap_iomem NULL #endif -#define snd_pcm_lib_mmap_vmalloc NULL - /** * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer * @dma: DMA number diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 78a2fdc38531..1e34e6381baa 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -778,7 +778,6 @@ static const struct snd_pcm_ops loopback_pcm_ops = { .trigger = loopback_trigger, .pointer = loopback_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static int loopback_pcm_new(struct loopback *loopback, diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 380a028469c4..ba80f459bdc5 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -883,7 +883,6 @@ static const struct snd_pcm_ops vx_pcm_playback_ops = { .trigger = vx_pcm_trigger, .pointer = vx_pcm_playback_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -1105,7 +1104,6 @@ static const struct snd_pcm_ops vx_pcm_capture_ops = { .trigger = vx_pcm_trigger, .pointer = vx_pcm_capture_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index e6adab3ef42e..ea9b86450580 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -373,7 +373,6 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 80351b29fe0d..bb3ef5ff3488 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -412,7 +412,6 @@ int snd_dice_create_pcm(struct snd_dice *dice) .pointer = capture_pointer, .ack = capture_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -425,7 +424,6 @@ int snd_dice_create_pcm(struct snd_dice *dice) .pointer = playback_pointer, .ack = playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; unsigned int capture, playback; diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 796f4b4645f5..fdcff0460c53 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -352,7 +352,6 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index e3c16308363d..bf47f9ec8703 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -383,7 +383,6 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff) .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 40faed5e6968..aed566d82726 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -397,7 +397,6 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 3919e186a30b..30957477e005 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -454,7 +454,6 @@ static int isight_create_pcm(struct isight *isight) .trigger = isight_trigger, .pointer = isight_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 4330220890e8..ab69d7e6ac05 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -363,7 +363,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) .pointer = capture_pointer, .ack = capture_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -376,7 +375,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) .pointer = playback_pointer, .ack = playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 3dd46285c0e2..b3f6503dd34d 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -389,7 +389,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -402,7 +401,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; unsigned int cap = 0; diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 6ec8ec634d4d..e4cc8990e195 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -279,7 +279,6 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 9fb68b35de5a..3ec9391a4736 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -685,7 +685,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = { @@ -698,7 +697,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops snd_sgio2audio_capture_ops = { @@ -711,7 +709,6 @@ static const struct snd_pcm_ops snd_sgio2audio_capture_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; /* diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 4a2354b5ae00..98a6863e933c 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -276,7 +276,6 @@ static const struct snd_pcm_ops pdacf_pcm_capture_ops = { .trigger = pdacf_pcm_trigger, .pointer = pdacf_pcm_capture_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 18686ffb0cd5..6478d10c4f4a 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -268,7 +268,6 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = { .hw_params = rt5514_spi_hw_params, .hw_free = rt5514_spi_hw_free, .pointer = rt5514_spi_pcm_pointer, - .mmap = snd_pcm_lib_mmap_vmalloc, .page = snd_pcm_lib_get_vmalloc_page, }; diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index 2dd2518a71d3..f8ef3e2a8ca0 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -565,7 +565,6 @@ static const struct snd_pcm_ops pcm_ops = { .trigger = usb6fire_pcm_trigger, .pointer = usb6fire_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static void usb6fire_pcm_init_urb(struct pcm_urb *urb, diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 15344d39a6cd..c6108a3d7f8f 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -348,7 +348,6 @@ static const struct snd_pcm_ops snd_usb_caiaq_ops = { .trigger = snd_usb_caiaq_pcm_trigger, .pointer = snd_usb_caiaq_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev, diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index 396c317115b1..e1fbb9cc9ea7 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -523,7 +523,6 @@ static const struct snd_pcm_ops pcm_ops = { .trigger = hiface_pcm_trigger, .pointer = hiface_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static int hiface_pcm_init_urb(struct pcm_urb *urb, diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 386fbfd5c617..a0b6d039017f 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -900,7 +900,6 @@ static const struct snd_pcm_ops capture_pcm_ops = { .trigger = capture_pcm_trigger, .pointer = capture_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops playback_pcm_ops = { @@ -913,7 +912,6 @@ static const struct snd_pcm_ops playback_pcm_ops = { .trigger = playback_pcm_trigger, .pointer = playback_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct uac_format_type_i_discrete_descriptor * diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 160f52c4871b..4b930fa47277 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1694,7 +1694,6 @@ static const struct snd_pcm_ops snd_usb_playback_ops = { .trigger = snd_usb_substream_playback_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops snd_usb_capture_ops = { @@ -1707,7 +1706,6 @@ static const struct snd_pcm_ops snd_usb_capture_ops = { .trigger = snd_usb_substream_capture_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct snd_pcm_ops snd_usb_playback_dev_ops = { -- cgit v1.2.3 From 95a48b7d4459948b6bacf809809cf01a7dc06d1d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jul 2018 23:00:54 +0200 Subject: ALSA: pcm: Add __force to cast in snd_pcm_lib_read/write() The snd_pcm_lib_read() and snd_pcm_lib_write() inline functions have the explicit cast from a user pointer to a kernel pointer, but they lacks of __force prefix. This fixes sparse warnings like: ./include/sound/pcm.h:1093:47: warning: cast removes address space of expression Fixes: 68541213720d ("ALSA: pcm: Direct in-kernel read/write support") Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/sound') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 1206045ccf03..d6bd3caf6878 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1090,14 +1090,14 @@ static inline snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, false); + return __snd_pcm_lib_xfer(substream, (void __force *)buf, true, frames, false); } static inline snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, false); + return __snd_pcm_lib_xfer(substream, (void __force *)buf, true, frames, false); } static inline snd_pcm_sframes_t -- cgit v1.2.3 From a6ea5fe95ab4a1a7af6d57429fe3ecde9acf5b5a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jul 2018 23:19:36 +0200 Subject: ALSA: hda: Fix implicit PCM format type conversion The PCM format type is defined with __bitwise, hence it can't be passed as integer but needs an explicit cast. In this patch, instead of the messy cast flood, define the format argument of snd_hdac_calc_stream_format() to be the proper snd_pcm_format_t type. This fixes sparse warnings like: sound/hda/hdac_device.c:760:38: warning: incorrect type in argument 1 (different base types) Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 3 ++- sound/hda/hdac_device.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/sound') diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 8305e7971035..6f1e1f3b3063 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -133,7 +134,7 @@ int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, hda_nid_t *start_id); unsigned int snd_hdac_calc_stream_format(unsigned int rate, unsigned int channels, - unsigned int format, + snd_pcm_format_t format, unsigned int maxbps, unsigned short spdif_ctls); int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 7ba100bb1c3f..dbf02a3a8d2f 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -738,7 +738,7 @@ static struct hda_rate_tbl rate_bits[] = { */ unsigned int snd_hdac_calc_stream_format(unsigned int rate, unsigned int channels, - unsigned int format, + snd_pcm_format_t format, unsigned int maxbps, unsigned short spdif_ctls) { -- cgit v1.2.3 From e5d3765b6c4cb3ba64295a4205a2f68a4e8fe083 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jul 2018 23:19:44 +0200 Subject: ALSA: sb: Fix sparse warning wrt PCM format type The PCM format type is with __bitwise, and it can't be converted from integer implicitly. Instead of an ugly cast, declare the function argument of snd_sb_csp_autoload() with the proper snd_pcm_format_t type. This fixes the sparse warnings like: sound/isa/sb/sb16_csp.c:743:22: warning: restricted snd_pcm_format_t degrades to integer Signed-off-by: Takashi Iwai --- include/sound/sb16_csp.h | 2 +- sound/isa/sb/sb16_csp.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/sound') diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h index c7c7788005e4..7817e88bd08d 100644 --- a/include/sound/sb16_csp.h +++ b/include/sound/sb16_csp.h @@ -46,7 +46,7 @@ enum { struct snd_sb_csp_ops { int (*csp_use) (struct snd_sb_csp * p); int (*csp_unuse) (struct snd_sb_csp * p); - int (*csp_autoload) (struct snd_sb_csp * p, int pcm_sfmt, int play_rec_mode); + int (*csp_autoload) (struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode); int (*csp_start) (struct snd_sb_csp * p, int sample_width, int channels); int (*csp_stop) (struct snd_sb_csp * p); int (*csp_qsound_transfer) (struct snd_sb_csp * p); diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index fa5780bb0c68..2210e7c72787 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -93,7 +93,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p, struct snd_sb_csp_microcode __user * code); static int snd_sb_csp_unload(struct snd_sb_csp * p); static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags); -static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec_mode); +static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode); static int snd_sb_csp_check_version(struct snd_sb_csp * p); static int snd_sb_csp_use(struct snd_sb_csp * p); @@ -726,7 +726,7 @@ static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags) * autoload hardware codec if necessary * return 0 if CSP is loaded and ready to run (p->running != 0) */ -static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec_mode) +static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode) { unsigned long flags; int err = 0; @@ -736,7 +736,7 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec return -EBUSY; /* autoload microcode only if requested hardware codec is not already loaded */ - if (((1 << pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) { + if (((1U << (__force int)pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) { p->running = SNDRV_SB_CSP_ST_AUTO; } else { switch (pcm_sfmt) { -- cgit v1.2.3 From f7debfe54090d1a1c38e1f070be20d83bb70a8e0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 29 Jul 2018 23:03:05 +0200 Subject: ALSA: seq: virmidi: Offload the output event processing The virmidi sequencer stuff tries to translate the rawmidi bytes to sequencer events and deliver the packets at trigger callback. The amount of the whole process of these translations and deliveries depends on the incoming rawmidi bytes, and we have no limit for that; this was the cause of a CPU soft lockup that had been reported and fixed recently. Although we've fixed the soft lockup by putting the temporary unlock and cond_resched(), it's rather a quick band aid. In this patch, meanwhile, the event parsing and delivery process is offloaded to a dedicated work, and the trigger callback just kicks it off. It has three merits, at least: - The processing is always done in a sleepable context, which can assure the event delivery with non-atomic flag without hackish is_atomic() usage. - Other relevant codes can be simplified, reducing the lines - It makes me happier Signed-off-by: Takashi Iwai --- include/sound/seq_virmidi.h | 1 + sound/core/seq/seq_virmidi.c | 100 ++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 54 deletions(-) (limited to 'include/sound') diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h index 695257ae64ac..d488dcfa3a4e 100644 --- a/include/sound/seq_virmidi.h +++ b/include/sound/seq_virmidi.h @@ -41,6 +41,7 @@ struct snd_virmidi { struct snd_seq_event event; struct snd_virmidi_dev *rdev; struct snd_rawmidi_substream *substream; + struct work_struct output_work; }; #define SNDRV_VIRMIDI_SUBSCRIBE (1<<0) diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 8ebbca554e99..67ea5d62cebc 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -154,70 +154,58 @@ static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, i } } -/* - * trigger rawmidi stream for output +/* process rawmidi bytes and send events; + * we need no lock here for vmidi->event since it's handled only in this work */ -static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_vmidi_output_work(struct work_struct *work) { - struct snd_virmidi *vmidi = substream->runtime->private_data; - int count, res; - unsigned char buf[32], *pbuf; - unsigned long flags; - bool check_resched = !in_atomic(); + struct snd_virmidi *vmidi; + struct snd_rawmidi_substream *substream; + unsigned char input; + int ret; + + vmidi = container_of(work, struct snd_virmidi, output_work); + substream = vmidi->substream; + + /* discard the outputs in dispatch mode unless subscribed */ + if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && + !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { + while (!snd_rawmidi_transmit_empty(substream)) + snd_rawmidi_transmit_ack(substream, 1); + return; + } - if (up) { - vmidi->trigger = 1; - if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && - !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - while (snd_rawmidi_transmit(substream, buf, - sizeof(buf)) > 0) { - /* ignored */ - } - return; - } - spin_lock_irqsave(&substream->runtime->lock, flags); + while (vmidi->trigger) { + if (snd_rawmidi_transmit(substream, &input, 1) != 1) + break; + if (snd_midi_event_encode_byte(vmidi->parser, input, + &vmidi->event) <= 0) + continue; if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { - if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - goto out; + ret = snd_seq_kernel_client_dispatch(vmidi->client, + &vmidi->event, + false, 0); vmidi->event.type = SNDRV_SEQ_EVENT_NONE; - } - while (1) { - count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); - if (count <= 0) + if (ret < 0) break; - pbuf = buf; - while (count > 0) { - res = snd_midi_event_encode(vmidi->parser, pbuf, count, &vmidi->event); - if (res < 0) { - snd_midi_event_reset_encode(vmidi->parser); - continue; - } - __snd_rawmidi_transmit_ack(substream, res); - pbuf += res; - count -= res; - if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { - if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - goto out; - vmidi->event.type = SNDRV_SEQ_EVENT_NONE; - } - } - if (!check_resched) - continue; - /* do temporary unlock & cond_resched() for avoiding - * CPU soft lockup, which may happen via a write from - * a huge rawmidi buffer - */ - spin_unlock_irqrestore(&substream->runtime->lock, flags); - cond_resched(); - spin_lock_irqsave(&substream->runtime->lock, flags); } - out: - spin_unlock_irqrestore(&substream->runtime->lock, flags); - } else { - vmidi->trigger = 0; + /* rawmidi input might be huge, allow to have a break */ + cond_resched(); } } +/* + * trigger rawmidi stream for output + */ +static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) +{ + struct snd_virmidi *vmidi = substream->runtime->private_data; + + vmidi->trigger = !!up; + if (up) + queue_work(system_highpri_wq, &vmidi->output_work); +} + /* * open rawmidi handle for input */ @@ -270,6 +258,7 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) vmidi->port = rdev->port; snd_virmidi_init_event(vmidi, &vmidi->event); vmidi->rdev = rdev; + INIT_WORK(&vmidi->output_work, snd_vmidi_output_work); runtime->private_data = vmidi; return 0; } @@ -299,6 +288,9 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream) { struct snd_virmidi *vmidi = substream->runtime->private_data; + + vmidi->trigger = 0; /* to be sure */ + cancel_work_sync(&vmidi->output_work); snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); -- cgit v1.2.3 From 89b4ab213feb11a5bece544cfa12374f66c2c47c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jul 2018 14:48:29 +0200 Subject: ALSA: seq: virmidi: Use READ_ONCE/WRITE_ONCE() macros The trigger flag in vmidi object can be referred in different contexts concurrently, hence it's better to be put with READ_ONCE() and WRITE_ONCE() macros to assure the accesses. Signed-off-by: Takashi Iwai --- include/sound/seq_virmidi.h | 2 +- sound/core/seq/seq_virmidi.c | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'include/sound') diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h index d488dcfa3a4e..796ce7772213 100644 --- a/include/sound/seq_virmidi.h +++ b/include/sound/seq_virmidi.h @@ -36,7 +36,7 @@ struct snd_virmidi { int seq_mode; int client; int port; - unsigned int trigger: 1; + bool trigger; struct snd_midi_event *parser; struct snd_seq_event event; struct snd_virmidi_dev *rdev; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 67ea5d62cebc..03ac5e72dbe6 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -89,7 +89,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, else down_read(&rdev->filelist_sem); list_for_each_entry(vmidi, &rdev->filelist, list) { - if (!vmidi->trigger) + if (!READ_ONCE(vmidi->trigger)) continue; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) @@ -147,11 +147,7 @@ static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, i { struct snd_virmidi *vmidi = substream->runtime->private_data; - if (up) { - vmidi->trigger = 1; - } else { - vmidi->trigger = 0; - } + WRITE_ONCE(vmidi->trigger, !!up); } /* process rawmidi bytes and send events; @@ -175,7 +171,7 @@ static void snd_vmidi_output_work(struct work_struct *work) return; } - while (vmidi->trigger) { + while (READ_ONCE(vmidi->trigger)) { if (snd_rawmidi_transmit(substream, &input, 1) != 1) break; if (snd_midi_event_encode_byte(vmidi->parser, input, @@ -201,7 +197,7 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, { struct snd_virmidi *vmidi = substream->runtime->private_data; - vmidi->trigger = !!up; + WRITE_ONCE(vmidi->trigger, !!up); if (up) queue_work(system_highpri_wq, &vmidi->output_work); } @@ -289,7 +285,7 @@ static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream) { struct snd_virmidi *vmidi = substream->runtime->private_data; - vmidi->trigger = 0; /* to be sure */ + WRITE_ONCE(vmidi->trigger, false); /* to be sure */ cancel_work_sync(&vmidi->output_work); snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; -- cgit v1.2.3 From ef965ad5a7697ff16e3be01954f5c57208e36c22 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Aug 2018 14:38:18 +0200 Subject: ALSA: seq: Minor cleanup of MIDI event parser helpers snd_midi_event_encode_byte() can never fail, and it can return rather true/false. Change the return type to bool, adjust the argument to receive a MIDI byte as unsigned char, and adjust the comment accordingly. This allows callers to drop error checks, which simplifies the code. Meanwhile, snd_midi_event_encode() helper is used only in seq_midi.c, and it can be better folded into it. This will reduce the total amount of lines in the end. Signed-off-by: Takashi Iwai --- include/sound/seq_midi_event.h | 6 ++---- sound/core/seq/oss/seq_oss_midi.c | 2 +- sound/core/seq/seq_midi.c | 24 ++++++++++------------ sound/core/seq/seq_midi_event.c | 42 +++++++-------------------------------- sound/core/seq/seq_virmidi.c | 4 ++-- 5 files changed, 22 insertions(+), 56 deletions(-) (limited to 'include/sound') diff --git a/include/sound/seq_midi_event.h b/include/sound/seq_midi_event.h index e40f43e6fc7b..2f135bccf457 100644 --- a/include/sound/seq_midi_event.h +++ b/include/sound/seq_midi_event.h @@ -43,10 +43,8 @@ void snd_midi_event_free(struct snd_midi_event *dev); void snd_midi_event_reset_encode(struct snd_midi_event *dev); void snd_midi_event_reset_decode(struct snd_midi_event *dev); void snd_midi_event_no_status(struct snd_midi_event *dev, int on); -/* encode from byte stream - return number of written bytes if success */ -long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count, - struct snd_seq_event *ev); -int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, struct snd_seq_event *ev); +bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, + struct snd_seq_event *ev); /* decode from event to bytes - return number of written bytes if success */ long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count, struct snd_seq_event *ev); diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 9debd1b8fd28..0d5f8b16d057 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -637,7 +637,7 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru if ((mdev = get_mididev(dp, dev)) == NULL) return -ENODEV; - if (snd_midi_event_encode_byte(mdev->coder, c, ev) > 0) { + if (snd_midi_event_encode_byte(mdev->coder, c, ev)) { snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); snd_use_lock_free(&mdev->use_lock); return 0; diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 5dd0ee258359..9e0dabd3ce5f 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -78,7 +78,7 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream) struct seq_midisynth *msynth; struct snd_seq_event ev; char buf[16], *pbuf; - long res, count; + long res; if (substream == NULL) return; @@ -94,19 +94,15 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream) if (msynth->parser == NULL) continue; pbuf = buf; - while (res > 0) { - count = snd_midi_event_encode(msynth->parser, pbuf, res, &ev); - if (count < 0) - break; - pbuf += count; - res -= count; - if (ev.type != SNDRV_SEQ_EVENT_NONE) { - ev.source.port = msynth->seq_port; - ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0); - /* clear event and reset header */ - memset(&ev, 0, sizeof(ev)); - } + while (res-- > 0) { + if (!snd_midi_event_encode_byte(msynth->parser, + *pbuf++, &ev)) + continue; + ev.source.port = msynth->seq_port; + ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; + snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0); + /* clear event and reset header */ + memset(&ev, 0, sizeof(ev)); } } } diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 90bbbdbeba03..53c0dfab90d6 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -214,45 +214,17 @@ int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize) } #endif /* 0 */ -/* - * read bytes and encode to sequencer event if finished - * return the size of encoded bytes - */ -long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count, - struct snd_seq_event *ev) -{ - long result = 0; - int rc; - - ev->type = SNDRV_SEQ_EVENT_NONE; - - while (count-- > 0) { - rc = snd_midi_event_encode_byte(dev, *buf++, ev); - result++; - if (rc < 0) - return rc; - else if (rc > 0) - return result; - } - - return result; -} -EXPORT_SYMBOL(snd_midi_event_encode); - /* * read one byte and encode to sequencer event: - * return 1 if MIDI bytes are encoded to an event - * 0 data is not finished - * negative for error + * return true if MIDI bytes are encoded to an event + * false data is not finished */ -int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, - struct snd_seq_event *ev) +bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, + struct snd_seq_event *ev) { - int rc = 0; + bool rc = false; unsigned long flags; - c &= 0xff; - if (c >= MIDI_CMD_COMMON_CLOCK) { /* real-time event */ ev->type = status_event[ST_SPECIAL + c - 0xf0].event; @@ -293,7 +265,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, status_event[dev->type].encode(dev, ev); if (dev->type >= ST_SPECIAL) dev->type = ST_INVALID; - rc = 1; + rc = true; } else if (dev->type == ST_SYSEX) { if (c == MIDI_CMD_COMMON_SYSEX_END || dev->read >= dev->bufsize) { @@ -306,7 +278,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, dev->read = 0; /* continue to parse */ else reset_encode(dev); /* all parsed */ - rc = 1; + rc = true; } } diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 03ac5e72dbe6..0c84926eb726 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -174,8 +174,8 @@ static void snd_vmidi_output_work(struct work_struct *work) while (READ_ONCE(vmidi->trigger)) { if (snd_rawmidi_transmit(substream, &input, 1) != 1) break; - if (snd_midi_event_encode_byte(vmidi->parser, input, - &vmidi->event) <= 0) + if (!snd_midi_event_encode_byte(vmidi->parser, input, + &vmidi->event)) continue; if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { ret = snd_seq_kernel_client_dispatch(vmidi->client, -- cgit v1.2.3