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 | 135 | RZV2H_RSPI_TX(writel, u32) |
| 136 | 136 | RZV2H_RSPI_TX(writew, u16) |
| 137 | 137 | RZV2H_RSPI_TX(writeb, u8) |
| 138 | +/* The read access size for RSPI_SPDR is fixed at 32 bits */ | |
| 138 | 139 | RZV2H_RSPI_RX(readl, u32) |
| 139 | −RZV2H_RSPI_RX(readw, u16) | |
| 140 | +RZV2H_RSPI_RX(readl, u16) | |
| 140 | 141 | RZV2H_RSPI_RX(readl, u8) |
| 141 | 142 | |
| 142 | 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 | 431 | if (timer) { |
| 432 | 432 | guard(spinlock_irq)(&timer->lock); |
| 433 | + if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) | |
| 434 | + return; /* already closed */ | |
| 433 | 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 | 978 | static int snd_timer_free(struct snd_timer *timer) |
| 977 | 979 | { |
| 980 | + struct snd_timer_instance *ti, *n; | |
| 981 | + | |
| 978 | 982 | if (!timer) |
| 979 | 983 | return 0; |
| 980 | 984 | |
| 981 | 985 | guard(mutex)(®ister_mutex); |
| 982 | 986 | if (! list_empty(&timer->open_list_head)) { |
| 983 | − struct list_head *p, *n; | |
| 984 | − struct snd_timer_instance *ti; | |
| 985 | − pr_warn("ALSA: timer %p is busy?\n", timer); | |
| 986 | − list_for_each_safe(p, n, &timer->open_list_head) { | |
| 987 | − list_del_init(p); | |
| 988 | − ti = list_entry(p, struct snd_timer_instance, open_list); | |
| 989 | − ti->timer = NULL; | |
| 987 | + list_for_each_entry_safe(ti, n, &timer->open_list_head, open_list) { | |
| 988 | + struct device *card_dev_to_put = NULL; | |
| 989 | + | |
| 990 | + snd_timer_close_locked(ti, &card_dev_to_put); | |
| 991 | + put_device(card_dev_to_put); | |
| 990 | 992 | } |
| 991 | 993 | } |
| 992 | 994 | list_del(&timer->device_list); |
| @@ -1809,6 +1811,7 @@ static int snd_timer_user_params(struct file *file, · 816 unmodified lines | ||
| 1809 | 1811 | struct snd_timer *t; |
| 1810 | 1812 | int err; |
| 1811 | 1813 | |
| 1814 | + guard(mutex)(®ister_mutex); | |
| 1812 | 1815 | tu = file->private_data; |
| 1813 | 1816 | if (!tu->timeri) |
| 1814 | 1817 | return -EBADFD; |
| @@ -808,6 +808,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { · 807 unmodified lines | ||
| 808 | 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 | 680 | struct wm_coeff_ctl *ctl = cs_ctl->priv; |
| 681 | 681 | |
| 682 | + if (!ctl) | |
| 683 | + return; | |
| 684 | + | |
| 682 | 685 | cancel_work_sync(&ctl->work); |
| 683 | 686 | |
| 684 | 687 | kfree(ctl->name); |
| @@ -199,6 +199,7 @@ loongson_pcm_pointer(struct snd_soc_component *component, · 198 unmodified lines | ||
| 199 | 199 | struct snd_pcm_substream *substream) |
| 200 | 200 | { |
| 201 | 201 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 202 | + struct device *dev = substream->pcm->card->dev; | |
| 202 | 203 | struct loongson_runtime_data *prtd = runtime->private_data; |
| 203 | 204 | struct loongson_dma_desc *desc; |
| 204 | 205 | snd_pcm_uframes_t x; |
| @@ -207,9 +208,16 @@ loongson_pcm_pointer(struct snd_soc_component *component, · 2 unmodified lines | ||
| 207 | 208 | desc = dma_desc_save(prtd); |
| 208 | 209 | addr = ((u64)desc->saddr_hi << 32) | desc->saddr; |
| 209 | 210 | |
| 210 | − x = bytes_to_frames(runtime, addr - runtime->dma_addr); | |
| 211 | − if (x == runtime->buffer_size) | |
| 211 | + if (addr < runtime->dma_addr || | |
| 212 | + addr > runtime->dma_addr + runtime->dma_bytes) { | |
| 213 | + dev_warn(dev, "WARNING! dma_addr:0x%llx\n", addr); | |
| 212 | 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 | 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 | 83 | static void sdca_dev_unregister(struct sdca_dev *sdev) |
| 84 | 84 | { |
| 85 | + if (!sdev) | |
| 86 | + return; | |
| 87 | + | |
| 85 | 88 | auxiliary_device_delete(&sdev->auxdev); |
| 86 | 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 | 94 | struct sdca_device_data *sdca_data = &slave->sdca_data; |
| 92 | 95 | int i; |
| 96 | + int ret; | |
| 93 | 97 | |
| 94 | 98 | for (i = 0; i < sdca_data->num_functions; i++) { |
| 95 | 99 | struct sdca_dev *func_dev; |
| 96 | 100 | |
| 97 | 101 | func_dev = sdca_dev_register(&slave->dev, |
| 98 | 102 | &sdca_data->function[i]); |
| 99 | − if (IS_ERR(func_dev)) | |
| 100 | − return PTR_ERR(func_dev); | |
| 103 | + if (IS_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 | 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 | 124 | struct sdca_device_data *sdca_data = &slave->sdca_data; |
| 112 | 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 | 131 | sdca_dev_unregister(sdca_data->function[i].func_dev); |
| 132 | + sdca_data->function[i].func_dev = NULL; | |
| 133 | + } | |
| 116 | 134 | } |
| 117 | 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 | 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 | 185 | snd_sof_ipc_msgs_rx(sdev); |
| 186 | 186 | acp_dsp_ipc_host_done(sdev); |
| 187 | 187 | ipc_irq = true; |
| 188 | 188 | } |
| 189 | 189 | |
| 190 | 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 | 192 | if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { |
| 193 | 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 | 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 | 407 | static int acp_memory_init(struct snd_sof_dev *sdev) |
| 381 | 408 | { |
| 382 | 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 | 412 | snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_CNTL_OFFSET, |
| 386 | 413 | ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK); |
| 414 | + acp_init_scratch_mem_ipc_flags(sdev); | |
| 387 | 415 | init_dma_descriptor(adata); |
| 388 | 416 | |
| 389 | 417 | return 0; |
| @@ -116,6 +116,8 @@ · 115 unmodified lines | ||
| 116 | 116 | #define ACP_SRAM_PAGE_COUNT 128 |
| 117 | 117 | #define ACP6X_SDW_MAX_MANAGER_COUNT 2 |
| 118 | 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 | 122 | enum clock_source { |
| 121 | 123 | ACP_CLOCK_96M = 0, |