Pull sound fixes from Takashi Iwai: "A few small fixes for the last spurt. All changes are small, mostly consisting of driver-specific fixes, along with two UAF fixes for the ALSA timer core. Core: - Two UAF fixes in ALSA timer core ASoC: - SDCA: Fix NULL pointer dereference - amd / yc: Add DMI quirk for ASUS ExpertBook PM1403CDA - SOF amd: Fix garbage/spurious warnings - wm_adsp: Fix potential NULL dereference when removing firmware controls - loongson: Fix negative position calculation - spi-rzv2h-rspi: Fix SPDR read access width on 16-bit RX path" * tag 'sound-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: ASoC: SDCA: fix NULL pointer dereference in sdca_dev_unregister_functions ASoC: loongson: Fix invalid position error in ls_pcm_pointer spi: rzv2h-rspi: Fix SPDR read access width for 16-bit RX ASoC: amd: yc: Add DMI quirk for ASUS EXPERTBOOK PM1403CDA ASoC: SOF: amd: set ipc flags to zero ASoC: SOF: amd: fix for ipc flags check ASoC: wm_adsp: Fix NULL dereference when removing firmware controls ALSA: timer: Fix UAF at snd_timer_user_params() ALSA: timer: Forcibly close timer instances at closing
Unified · Split
| @@ -135,8 +135,9 @@ static inline void rzv2h_rspi_rx_##type(struct rzv2h_rspi_priv *rspi, \ · 134 unmodified lines | |||
| 135 | RZV2H_RSPI_TX(writel, u32) | 135 | RZV2H_RSPI_TX(writel, u32) |
| 136 | RZV2H_RSPI_TX(writew, u16) | 136 | RZV2H_RSPI_TX(writew, u16) |
| 137 | RZV2H_RSPI_TX(writeb, u8) | 137 | RZV2H_RSPI_TX(writeb, u8) |
| 138 | /* The read access size for RSPI_SPDR is fixed at 32 bits */ | ||
| 138 | RZV2H_RSPI_RX(readl, u32) | 139 | RZV2H_RSPI_RX(readl, u32) |
| 139 | RZV2H_RSPI_RX(readw, u16) | 140 | RZV2H_RSPI_RX(readl, u16) |
| 140 | RZV2H_RSPI_RX(readl, u8) | 141 | RZV2H_RSPI_RX(readl, u8) |
| 141 | 142 | ||
| 142 | static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi, | 143 | static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi, |
| @@ -430,6 +430,8 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, · 429 unmodified lines | |||
| 430 | 430 | ||
| 431 | if (timer) { | 431 | if (timer) { |
| 432 | guard(spinlock_irq)(&timer->lock); | 432 | guard(spinlock_irq)(&timer->lock); |
| 433 | if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) | ||
| 434 | return; /* already closed */ | ||
| 433 | timeri->flags |= SNDRV_TIMER_IFLG_DEAD; | 435 | timeri->flags |= SNDRV_TIMER_IFLG_DEAD; |
| 434 | } | 436 | } |
| 435 | 437 | ||
| @@ -975,18 +977,18 @@ EXPORT_SYMBOL(snd_timer_new); · 539 unmodified lines | |||
| 975 | 977 | ||
| 976 | static int snd_timer_free(struct snd_timer *timer) | 978 | static int snd_timer_free(struct snd_timer *timer) |
| 977 | { | 979 | { |
| 980 | struct snd_timer_instance *ti, *n; | ||
| 981 | |||
| 978 | if (!timer) | 982 | if (!timer) |
| 979 | return 0; | 983 | return 0; |
| 980 | 984 | ||
| 981 | guard(mutex)(®ister_mutex); | 985 | guard(mutex)(®ister_mutex); |
| 982 | if (! list_empty(&timer->open_list_head)) { | 986 | if (! list_empty(&timer->open_list_head)) { |
| 983 | struct list_head *p, *n; | 987 | list_for_each_entry_safe(ti, n, &timer->open_list_head, open_list) { |
| 984 | struct snd_timer_instance *ti; | 988 | struct device *card_dev_to_put = NULL; |
| 985 | pr_warn("ALSA: timer %p is busy?\n", timer); | 989 | |
| 986 | list_for_each_safe(p, n, &timer->open_list_head) { | 990 | snd_timer_close_locked(ti, &card_dev_to_put); |
| 987 | list_del_init(p); | 991 | put_device(card_dev_to_put); |
| 988 | ti = list_entry(p, struct snd_timer_instance, open_list); | ||
| 989 | ti->timer = NULL; | ||
| 990 | } | 992 | } |
| 991 | } | 993 | } |
| 992 | list_del(&timer->device_list); | 994 | list_del(&timer->device_list); |
| @@ -1809,6 +1811,7 @@ static int snd_timer_user_params(struct file *file, · 816 unmodified lines | |||
| 1809 | struct snd_timer *t; | 1811 | struct snd_timer *t; |
| 1810 | int err; | 1812 | int err; |
| 1811 | 1813 | ||
| 1814 | guard(mutex)(®ister_mutex); | ||
| 1812 | tu = file->private_data; | 1815 | tu = file->private_data; |
| 1813 | if (!tu->timeri) | 1816 | if (!tu->timeri) |
| 1814 | return -EBADFD; | 1817 | return -EBADFD; |
| @@ -808,6 +808,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { · 807 unmodified lines | |||
| 808 | DMI_MATCH(DMI_BOARD_NAME, "MS-17LN"), | 808 | DMI_MATCH(DMI_BOARD_NAME, "MS-17LN"), |
| 809 | } | 809 | } |
| 810 | }, | 810 | }, |
| 811 | { | ||
| 812 | .driver_data = &acp6x_card, | ||
| 813 | .matches = { | ||
| 814 | DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), | ||
| 815 | DMI_MATCH(DMI_BOARD_NAME, "PM1403CDA"), | ||
| 816 | } | ||
| 817 | }, | ||
| 811 | {} | 818 | {} |
| 812 | }; | 819 | }; |
| 813 | 820 | ||
| @@ -679,6 +679,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) · 678 unmodified lines | |||
| 679 | { | 679 | { |
| 680 | struct wm_coeff_ctl *ctl = cs_ctl->priv; | 680 | struct wm_coeff_ctl *ctl = cs_ctl->priv; |
| 681 | 681 | ||
| 682 | if (!ctl) | ||
| 683 | return; | ||
| 684 | |||
| 682 | cancel_work_sync(&ctl->work); | 685 | cancel_work_sync(&ctl->work); |
| 683 | 686 | ||
| 684 | kfree(ctl->name); | 687 | kfree(ctl->name); |
| @@ -199,6 +199,7 @@ loongson_pcm_pointer(struct snd_soc_component *component, · 198 unmodified lines | |||
| 199 | struct snd_pcm_substream *substream) | 199 | struct snd_pcm_substream *substream) |
| 200 | { | 200 | { |
| 201 | struct snd_pcm_runtime *runtime = substream->runtime; | 201 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 202 | struct device *dev = substream->pcm->card->dev; | ||
| 202 | struct loongson_runtime_data *prtd = runtime->private_data; | 203 | struct loongson_runtime_data *prtd = runtime->private_data; |
| 203 | struct loongson_dma_desc *desc; | 204 | struct loongson_dma_desc *desc; |
| 204 | snd_pcm_uframes_t x; | 205 | snd_pcm_uframes_t x; |
| @@ -207,9 +208,16 @@ loongson_pcm_pointer(struct snd_soc_component *component, · 2 unmodified lines | |||
| 207 | desc = dma_desc_save(prtd); | 208 | desc = dma_desc_save(prtd); |
| 208 | addr = ((u64)desc->saddr_hi << 32) | desc->saddr; | 209 | addr = ((u64)desc->saddr_hi << 32) | desc->saddr; |
| 209 | 210 | ||
| 210 | x = bytes_to_frames(runtime, addr - runtime->dma_addr); | 211 | if (addr < runtime->dma_addr || |
| 211 | if (x == runtime->buffer_size) | 212 | addr > runtime->dma_addr + runtime->dma_bytes) { |
| 213 | dev_warn(dev, "WARNING! dma_addr:0x%llx\n", addr); | ||
| 212 | x = 0; | 214 | x = 0; |
| 215 | } else { | ||
| 216 | x = bytes_to_frames(runtime, addr - runtime->dma_addr); | ||
| 217 | if (x == runtime->buffer_size) | ||
| 218 | x = 0; | ||
| 219 | } | ||
| 220 | |||
| 213 | return x; | 221 | return x; |
| 214 | } | 222 | } |
| 215 | 223 | ||
| @@ -82,6 +82,9 @@ static struct sdca_dev *sdca_dev_register(struct device *parent, · 81 unmodified lines | |||
| 82 | 82 | ||
| 83 | static void sdca_dev_unregister(struct sdca_dev *sdev) | 83 | static void sdca_dev_unregister(struct sdca_dev *sdev) |
| 84 | { | 84 | { |
| 85 | if (!sdev) | ||
| 86 | return; | ||
| 87 | |||
| 85 | auxiliary_device_delete(&sdev->auxdev); | 88 | auxiliary_device_delete(&sdev->auxdev); |
| 86 | auxiliary_device_uninit(&sdev->auxdev); | 89 | auxiliary_device_uninit(&sdev->auxdev); |
| 87 | } | 90 | } |
| @@ -90,14 +93,24 @@ int sdca_dev_register_functions(struct sdw_slave *slave) · 2 unmodified lines | |||
| 90 | { | 93 | { |
| 91 | struct sdca_device_data *sdca_data = &slave->sdca_data; | 94 | struct sdca_device_data *sdca_data = &slave->sdca_data; |
| 92 | int i; | 95 | int i; |
| 96 | int ret; | ||
| 93 | 97 | ||
| 94 | for (i = 0; i < sdca_data->num_functions; i++) { | 98 | for (i = 0; i < sdca_data->num_functions; i++) { |
| 95 | struct sdca_dev *func_dev; | 99 | struct sdca_dev *func_dev; |
| 96 | 100 | ||
| 97 | func_dev = sdca_dev_register(&slave->dev, | 101 | func_dev = sdca_dev_register(&slave->dev, |
| 98 | &sdca_data->function[i]); | 102 | &sdca_data->function[i]); |
| 99 | if (IS_ERR(func_dev)) | 103 | if (IS_ERR(func_dev)) { |
| 100 | return PTR_ERR(func_dev); | 104 | ret = PTR_ERR(func_dev); |
| 105 | /* | ||
| 106 | * Unregister functions that were successfully | ||
| 107 | * registered before this failure. This also | ||
| 108 | * sets func_dev to NULL so the caller will not | ||
| 109 | * try to unregister them again. | ||
| 110 | */ | ||
| 111 | sdca_dev_unregister_functions(slave); | ||
| 112 | return ret; | ||
| 113 | } | ||
| 101 | 114 | ||
| 102 | sdca_data->function[i].func_dev = func_dev; | 115 | sdca_data->function[i].func_dev = func_dev; |
| 103 | } | 116 | } |
| @@ -111,7 +124,12 @@ void sdca_dev_unregister_functions(struct sdw_slave *slave) · 7 unmodified lines | |||
| 111 | struct sdca_device_data *sdca_data = &slave->sdca_data; | 124 | struct sdca_device_data *sdca_data = &slave->sdca_data; |
| 112 | int i; | 125 | int i; |
| 113 | 126 | ||
| 114 | for (i = 0; i < sdca_data->num_functions; i++) | 127 | for (i = 0; i < sdca_data->num_functions; i++) { |
| 128 | if (!sdca_data->function[i].func_dev) | ||
| 129 | continue; | ||
| 130 | |||
| 115 | sdca_dev_unregister(sdca_data->function[i].func_dev); | 131 | sdca_dev_unregister(sdca_data->function[i].func_dev); |
| 132 | sdca_data->function[i].func_dev = NULL; | ||
| 133 | } | ||
| 116 | } | 134 | } |
| 117 | EXPORT_SYMBOL_NS(sdca_dev_unregister_functions, "SND_SOC_SDCA"); | 135 | EXPORT_SYMBOL_NS(sdca_dev_unregister_functions, "SND_SOC_SDCA"); |
| @@ -181,14 +181,14 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) · 180 unmodified lines | |||
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write); | 183 | dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write); |
| 184 | if (dsp_msg) { | 184 | if (dsp_msg == ACP_DSP_MSG_SET) { |
| 185 | snd_sof_ipc_msgs_rx(sdev); | 185 | snd_sof_ipc_msgs_rx(sdev); |
| 186 | acp_dsp_ipc_host_done(sdev); | 186 | acp_dsp_ipc_host_done(sdev); |
| 187 | ipc_irq = true; | 187 | ipc_irq = true; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); | 190 | dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); |
| 191 | if (dsp_ack) { | 191 | if (dsp_ack == ACP_DSP_ACK_SET) { |
| 192 | if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { | 192 | if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { |
| 193 | guard(spinlock_irq)(&sdev->ipc_lock); | 193 | guard(spinlock_irq)(&sdev->ipc_lock); |
| 194 | 194 | ||
| @@ -377,6 +377,33 @@ void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, · 376 unmodified lines | |||
| 377 | snd_sof_dsp_write(sdev, ACP_DSP_BAR, reg_offset + i, src[j]); | 377 | snd_sof_dsp_write(sdev, ACP_DSP_BAR, reg_offset + i, src[j]); |
| 378 | } | 378 | } |
| 379 | 379 | ||
| 380 | static int acp_init_scratch_mem_ipc_flags(struct snd_sof_dev *sdev) | ||
| 381 | { | ||
| 382 | u32 dsp_msg_write, dsp_ack_write, host_msg_write, host_ack_write; | ||
| 383 | |||
| 384 | dsp_msg_write = sdev->debug_box.offset + | ||
| 385 | offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); | ||
| 386 | dsp_ack_write = sdev->debug_box.offset + | ||
| 387 | offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); | ||
| 388 | host_msg_write = sdev->debug_box.offset + | ||
| 389 | offsetof(struct scratch_ipc_conf, sof_host_msg_write); | ||
| 390 | host_ack_write = sdev->debug_box.offset + | ||
| 391 | offsetof(struct scratch_ipc_conf, sof_host_ack_write); | ||
| 392 | /* Initialize host message write flag */ | ||
| 393 | snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_msg_write, 0); | ||
| 394 | |||
| 395 | /* Initialize host ack write flag */ | ||
| 396 | snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_ack_write, 0); | ||
| 397 | |||
| 398 | /* Initialize DSP message write flag */ | ||
| 399 | snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write, 0); | ||
| 400 | |||
| 401 | /* Initialize DSP ack write flag */ | ||
| 402 | snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write, 0); | ||
| 403 | |||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 380 | static int acp_memory_init(struct snd_sof_dev *sdev) | 407 | static int acp_memory_init(struct snd_sof_dev *sdev) |
| 381 | { | 408 | { |
| 382 | struct acp_dev_data *adata = sdev->pdata->hw_pdata; | 409 | struct acp_dev_data *adata = sdev->pdata->hw_pdata; |
| @@ -384,6 +411,7 @@ static int acp_memory_init(struct snd_sof_dev *sdev) · 1 unmodified line | |||
| 384 | 411 | ||
| 385 | snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_CNTL_OFFSET, | 412 | snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_CNTL_OFFSET, |
| 386 | ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK); | 413 | ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK); |
| 414 | acp_init_scratch_mem_ipc_flags(sdev); | ||
| 387 | init_dma_descriptor(adata); | 415 | init_dma_descriptor(adata); |
| 388 | 416 | ||
| 389 | return 0; | 417 | return 0; |
| @@ -116,6 +116,8 @@ · 115 unmodified lines | |||
| 116 | #define ACP_SRAM_PAGE_COUNT 128 | 116 | #define ACP_SRAM_PAGE_COUNT 128 |
| 117 | #define ACP6X_SDW_MAX_MANAGER_COUNT 2 | 117 | #define ACP6X_SDW_MAX_MANAGER_COUNT 2 |
| 118 | #define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT | 118 | #define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT |
| 119 | #define ACP_DSP_MSG_SET 1 | ||
| 120 | #define ACP_DSP_ACK_SET 1 | ||
| 119 | 121 | ||
| 120 | enum clock_source { | 122 | enum clock_source { |
| 121 | ACP_CLOCK_96M = 0, | 123 | ACP_CLOCK_96M = 0, |