ALSA: hda - Fix memory leak and error handling in CA0132 DSP loader
authorTakashi Iwai <tiwai@suse.de>
Sun, 10 Feb 2013 10:58:40 +0000 (11:58 +0100)
committerTakashi Iwai <tiwai@suse.de>
Sun, 10 Feb 2013 10:58:40 +0000 (11:58 +0100)
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>
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_ca0132.c

index 1f8ce216edbb001cbd63d898ea7ad0a5de887d0b..bb9179e46796343bc2f405de97049e91a4fcca4e 100644 (file)
@@ -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);
 }
index 710dae81fc8e0f868113b29932dc926cef117847..fb7a32e730af40de6895f693dede5b51914c1e32 100644 (file)
@@ -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);