From b3667bd7579e6d4dfe709315f13cff9bc9ee9053 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 10 Feb 2013 11:58:40 +0100 Subject: 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: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1f8ce21..bb9179e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2628,8 +2628,9 @@ static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format, snd_dma_pci_data(chip->pci), byte_size, bufp); if (err < 0) - goto error; + goto unlock; + mark_pages_wc(chip, bufp, true); azx_dev = azx_get_dsp_loader_dev(chip); azx_dev->bufsize = 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, return azx_dev->stream_tag; error: + mark_pages_wc(chip, bufp, false); + snd_dma_free_pages(bufp); +unlock: snd_hda_unlock_devices(bus); return err; } @@ -2673,6 +2677,9 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, struct azx *chip = bus->private_data; struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); + if (!dmab->area) + return; + /* reset BDL address */ azx_sd_writel(azx_dev, SD_BDLPL, 0); azx_sd_writel(azx_dev, SD_BDLPU, 0); @@ -2681,7 +2688,9 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, azx_dev->period_bytes = 0; azx_dev->format_val = 0; + mark_pages_wc(chip, dmab, false); snd_dma_free_pages(dmab); + dmab->area = NULL; snd_hda_unlock_devices(bus); } diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 710dae8..fb7a32e 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2065,7 +2065,7 @@ static int dma_reset(struct dma_engine *dma) struct ca0132_spec *spec = codec->spec; int status; - if (dma->dmab) + if (dma->dmab->area) snd_hda_codec_load_dsp_cleanup(codec, dma->dmab); status = snd_hda_codec_load_dsp_prepare(codec, @@ -2357,10 +2357,14 @@ static int dspxfr_one_seg(struct hda_codec *codec, chip_addx_remainder, data_remainder, remainder_words); + if (status < 0) + return status; remainder_words = 0; } if (hci_write) { status = dspxfr_hci_write(codec, hci_write); + if (status < 0) + return status; hci_write = NULL; } @@ -2376,7 +2380,7 @@ static int dspxfr_one_seg(struct hda_codec *codec, snd_printdd(KERN_INFO "+++++ DMA complete"); dma_set_state(dma_engine, DMA_STATE_STOP); - dma_reset(dma_engine); + status = dma_reset(dma_engine); if (status < 0) return status; @@ -2517,7 +2521,7 @@ exit: if (ovly && (dma_chan != INVALID_DMA_CHANNEL)) 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); kfree(dma_engine->dmab); kfree(dma_engine); -- cgit v0.10.2