Commit b3667bd7 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Fix memory leak and error handling in CA0132 DSP loader

This patch fixes a few obvious bugs in DSP loader stuff:
- Fix possible memory leaks in the error path
- Avoid double-free calls in dma_reset()
- Properly set/unset WC bits for DMA buffers
- Add missing error status checks
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6d67530e
...@@ -2628,8 +2628,9 @@ static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format, ...@@ -2628,8 +2628,9 @@ static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
snd_dma_pci_data(chip->pci), snd_dma_pci_data(chip->pci),
byte_size, bufp); byte_size, bufp);
if (err < 0) if (err < 0)
goto error; goto unlock;
mark_pages_wc(chip, bufp, true);
azx_dev = azx_get_dsp_loader_dev(chip); azx_dev = azx_get_dsp_loader_dev(chip);
azx_dev->bufsize = byte_size; azx_dev->bufsize = byte_size;
azx_dev->period_bytes = byte_size; azx_dev->period_bytes = byte_size;
...@@ -2651,6 +2652,9 @@ static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format, ...@@ -2651,6 +2652,9 @@ static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
return azx_dev->stream_tag; return azx_dev->stream_tag;
error: error:
mark_pages_wc(chip, bufp, false);
snd_dma_free_pages(bufp);
unlock:
snd_hda_unlock_devices(bus); snd_hda_unlock_devices(bus);
return err; return err;
} }
...@@ -2673,6 +2677,9 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, ...@@ -2673,6 +2677,9 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
struct azx *chip = bus->private_data; struct azx *chip = bus->private_data;
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
if (!dmab->area)
return;
/* reset BDL address */ /* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0); azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0); azx_sd_writel(azx_dev, SD_BDLPU, 0);
...@@ -2681,7 +2688,9 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, ...@@ -2681,7 +2688,9 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
azx_dev->period_bytes = 0; azx_dev->period_bytes = 0;
azx_dev->format_val = 0; azx_dev->format_val = 0;
mark_pages_wc(chip, dmab, false);
snd_dma_free_pages(dmab); snd_dma_free_pages(dmab);
dmab->area = NULL;
snd_hda_unlock_devices(bus); snd_hda_unlock_devices(bus);
} }
......
...@@ -2065,7 +2065,7 @@ static int dma_reset(struct dma_engine *dma) ...@@ -2065,7 +2065,7 @@ static int dma_reset(struct dma_engine *dma)
struct ca0132_spec *spec = codec->spec; struct ca0132_spec *spec = codec->spec;
int status; int status;
if (dma->dmab) if (dma->dmab->area)
snd_hda_codec_load_dsp_cleanup(codec, dma->dmab); snd_hda_codec_load_dsp_cleanup(codec, dma->dmab);
status = snd_hda_codec_load_dsp_prepare(codec, status = snd_hda_codec_load_dsp_prepare(codec,
...@@ -2357,10 +2357,14 @@ static int dspxfr_one_seg(struct hda_codec *codec, ...@@ -2357,10 +2357,14 @@ static int dspxfr_one_seg(struct hda_codec *codec,
chip_addx_remainder, chip_addx_remainder,
data_remainder, data_remainder,
remainder_words); remainder_words);
if (status < 0)
return status;
remainder_words = 0; remainder_words = 0;
} }
if (hci_write) { if (hci_write) {
status = dspxfr_hci_write(codec, hci_write); status = dspxfr_hci_write(codec, hci_write);
if (status < 0)
return status;
hci_write = NULL; hci_write = NULL;
} }
...@@ -2376,7 +2380,7 @@ static int dspxfr_one_seg(struct hda_codec *codec, ...@@ -2376,7 +2380,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
snd_printdd(KERN_INFO "+++++ DMA complete"); snd_printdd(KERN_INFO "+++++ DMA complete");
dma_set_state(dma_engine, DMA_STATE_STOP); dma_set_state(dma_engine, DMA_STATE_STOP);
dma_reset(dma_engine); status = dma_reset(dma_engine);
if (status < 0) if (status < 0)
return status; return status;
...@@ -2517,7 +2521,7 @@ static int dspxfr_image(struct hda_codec *codec, ...@@ -2517,7 +2521,7 @@ static int dspxfr_image(struct hda_codec *codec,
if (ovly && (dma_chan != INVALID_DMA_CHANNEL)) if (ovly && (dma_chan != INVALID_DMA_CHANNEL))
dspio_free_dma_chan(codec, dma_chan); dspio_free_dma_chan(codec, dma_chan);
if (dma_engine->dmab) if (dma_engine->dmab->area)
snd_hda_codec_load_dsp_cleanup(codec, dma_engine->dmab); snd_hda_codec_load_dsp_cleanup(codec, dma_engine->dmab);
kfree(dma_engine->dmab); kfree(dma_engine->dmab);
kfree(dma_engine); kfree(dma_engine);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment