summaryrefslogtreecommitdiff
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-02-10 14:58:40 +0400
committerTakashi Iwai <tiwai@suse.de>2013-02-10 14:58:40 +0400
commitb3667bd7579e6d4dfe709315f13cff9bc9ee9053 (patch)
tree6edfef15c2a1598de92c6fff7f17700ffb4ec53c /sound/pci
parent6d67530e2c73e375b9204eba10ee2d589ba353ae (diff)
downloadlinux-b3667bd7579e6d4dfe709315f13cff9bc9ee9053.tar.xz
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 <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_intel.c11
-rw-r--r--sound/pci/hda/patch_ca0132.c10
2 files changed, 17 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1f8ce216edbb..bb9179e46796 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 710dae81fc8e..fb7a32e730af 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);