diff options
author | Liam Girdwood <liam.r.girdwood@linux.intel.com> | 2014-05-02 11:56:30 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-05-02 12:53:01 -0400 |
commit | 0b708c87f66a15190fb43661c2320fd48c4dc6c8 (patch) | |
tree | 2f8f4c323abdb2d39951be86f361219b74ecacd9 /sound/soc | |
parent | 84fbdd58614e35108ece5c79ada33443dbcdaf37 (diff) |
ASoC: Intel: Fix Haswell/Broadwell DSP page table creation.
Fix page table creation on Haswell and Broadwell to remove unsafe
virt_to_phys mappings and use more portable SG buffer. Use audio buffer
APIs to allocate DMA buffers.
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/intel/sst-haswell-pcm.c | 58 |
1 files changed, 31 insertions, 27 deletions
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 0a32dd13a23d..dc53f501c64c 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -107,7 +107,7 @@ struct hsw_priv_data { | |||
107 | struct sst_hsw *hsw; | 107 | struct sst_hsw *hsw; |
108 | 108 | ||
109 | /* page tables */ | 109 | /* page tables */ |
110 | unsigned char *pcm_pg[HSW_PCM_COUNT][2]; | 110 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; |
111 | 111 | ||
112 | /* DAI data */ | 112 | /* DAI data */ |
113 | struct hsw_pcm_data pcm[HSW_PCM_COUNT]; | 113 | struct hsw_pcm_data pcm[HSW_PCM_COUNT]; |
@@ -273,28 +273,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { | |||
273 | }; | 273 | }; |
274 | 274 | ||
275 | /* Create DMA buffer page table for DSP */ | 275 | /* Create DMA buffer page table for DSP */ |
276 | static int create_adsp_page_table(struct hsw_priv_data *pdata, | 276 | static int create_adsp_page_table(struct snd_pcm_substream *substream, |
277 | struct snd_soc_pcm_runtime *rtd, | 277 | struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd, |
278 | unsigned char *dma_area, size_t size, int pcm, int stream) | 278 | unsigned char *dma_area, size_t size, int pcm) |
279 | { | 279 | { |
280 | int i, pages; | 280 | struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); |
281 | int i, pages, stream = substream->stream; | ||
281 | 282 | ||
282 | if (size % PAGE_SIZE) | 283 | pages = snd_sgbuf_aligned_pages(size); |
283 | pages = (size / PAGE_SIZE) + 1; | ||
284 | else | ||
285 | pages = size / PAGE_SIZE; | ||
286 | 284 | ||
287 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", | 285 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", |
288 | dma_area, size, pages); | 286 | dma_area, size, pages); |
289 | 287 | ||
290 | for (i = 0; i < pages; i++) { | 288 | for (i = 0; i < pages; i++) { |
291 | u32 idx = (((i << 2) + i)) >> 1; | 289 | u32 idx = (((i << 2) + i)) >> 1; |
292 | u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; | 290 | u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; |
293 | u32 *pg_table; | 291 | u32 *pg_table; |
294 | 292 | ||
295 | dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); | 293 | dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); |
296 | 294 | ||
297 | pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); | 295 | pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx); |
298 | 296 | ||
299 | if (i & 1) | 297 | if (i & 1) |
300 | *pg_table |= (pfn << 4); | 298 | *pg_table |= (pfn << 4); |
@@ -317,6 +315,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
317 | struct sst_hsw *hsw = pdata->hsw; | 315 | struct sst_hsw *hsw = pdata->hsw; |
318 | struct sst_module *module_data; | 316 | struct sst_module *module_data; |
319 | struct sst_dsp *dsp; | 317 | struct sst_dsp *dsp; |
318 | struct snd_dma_buffer *dmab; | ||
320 | enum sst_hsw_stream_type stream_type; | 319 | enum sst_hsw_stream_type stream_type; |
321 | enum sst_hsw_stream_path_id path_id; | 320 | enum sst_hsw_stream_path_id path_id; |
322 | u32 rate, bits, map, pages, module_id; | 321 | u32 rate, bits, map, pages, module_id; |
@@ -416,8 +415,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
416 | return ret; | 415 | return ret; |
417 | } | 416 | } |
418 | 417 | ||
419 | ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, | 418 | dmab = snd_pcm_get_dma_buf(substream); |
420 | runtime->dma_bytes, rtd->cpu_dai->id, substream->stream); | 419 | |
420 | ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area, | ||
421 | runtime->dma_bytes, rtd->cpu_dai->id); | ||
421 | if (ret < 0) | 422 | if (ret < 0) |
422 | return ret; | 423 | return ret; |
423 | 424 | ||
@@ -430,9 +431,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
430 | pages = runtime->dma_bytes / PAGE_SIZE; | 431 | pages = runtime->dma_bytes / PAGE_SIZE; |
431 | 432 | ||
432 | ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, | 433 | ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, |
433 | virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), | 434 | pdata->dmab[rtd->cpu_dai->id][substream->stream].addr, |
434 | pages, runtime->dma_bytes, 0, | 435 | pages, runtime->dma_bytes, 0, |
435 | (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); | 436 | snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT); |
436 | if (ret < 0) { | 437 | if (ret < 0) { |
437 | dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); | 438 | dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); |
438 | return ret; | 439 | return ret; |
@@ -621,7 +622,7 @@ static struct snd_pcm_ops hsw_pcm_ops = { | |||
621 | .hw_free = hsw_pcm_hw_free, | 622 | .hw_free = hsw_pcm_hw_free, |
622 | .trigger = hsw_pcm_trigger, | 623 | .trigger = hsw_pcm_trigger, |
623 | .pointer = hsw_pcm_pointer, | 624 | .pointer = hsw_pcm_pointer, |
624 | .mmap = snd_pcm_lib_default_mmap, | 625 | .page = snd_pcm_sgbuf_ops_page, |
625 | }; | 626 | }; |
626 | 627 | ||
627 | static void hsw_pcm_free(struct snd_pcm *pcm) | 628 | static void hsw_pcm_free(struct snd_pcm *pcm) |
@@ -641,7 +642,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
641 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | 642 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || |
642 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | 643 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { |
643 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | 644 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, |
644 | SNDRV_DMA_TYPE_DEV, | 645 | SNDRV_DMA_TYPE_DEV_SG, |
645 | rtd->card->dev, | 646 | rtd->card->dev, |
646 | hsw_pcm_hardware.buffer_bytes_max, | 647 | hsw_pcm_hardware.buffer_bytes_max, |
647 | hsw_pcm_hardware.buffer_bytes_max); | 648 | hsw_pcm_hardware.buffer_bytes_max); |
@@ -742,7 +743,8 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
742 | { | 743 | { |
743 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | 744 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); |
744 | struct hsw_priv_data *priv_data; | 745 | struct hsw_priv_data *priv_data; |
745 | int i; | 746 | struct device *dma_dev = pdata->dma_dev; |
747 | int i, ret = 0; | ||
746 | 748 | ||
747 | if (!pdata) | 749 | if (!pdata) |
748 | return -ENODEV; | 750 | return -ENODEV; |
@@ -758,15 +760,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
758 | 760 | ||
759 | /* playback */ | 761 | /* playback */ |
760 | if (hsw_dais[i].playback.channels_min) { | 762 | if (hsw_dais[i].playback.channels_min) { |
761 | priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); | 763 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, |
762 | if (priv_data->pcm_pg[i][0] == NULL) | 764 | PAGE_SIZE, &priv_data->dmab[i][0]); |
765 | if (ret < 0) | ||
763 | goto err; | 766 | goto err; |
764 | } | 767 | } |
765 | 768 | ||
766 | /* capture */ | 769 | /* capture */ |
767 | if (hsw_dais[i].capture.channels_min) { | 770 | if (hsw_dais[i].capture.channels_min) { |
768 | priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); | 771 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, |
769 | if (priv_data->pcm_pg[i][1] == NULL) | 772 | PAGE_SIZE, &priv_data->dmab[i][1]); |
773 | if (ret < 0) | ||
770 | goto err; | 774 | goto err; |
771 | } | 775 | } |
772 | } | 776 | } |
@@ -776,11 +780,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
776 | err: | 780 | err: |
777 | for (;i >= 0; i--) { | 781 | for (;i >= 0; i--) { |
778 | if (hsw_dais[i].playback.channels_min) | 782 | if (hsw_dais[i].playback.channels_min) |
779 | kfree(priv_data->pcm_pg[i][0]); | 783 | snd_dma_free_pages(&priv_data->dmab[i][0]); |
780 | if (hsw_dais[i].capture.channels_min) | 784 | if (hsw_dais[i].capture.channels_min) |
781 | kfree(priv_data->pcm_pg[i][1]); | 785 | snd_dma_free_pages(&priv_data->dmab[i][1]); |
782 | } | 786 | } |
783 | return -ENOMEM; | 787 | return ret; |
784 | } | 788 | } |
785 | 789 | ||
786 | static int hsw_pcm_remove(struct snd_soc_platform *platform) | 790 | static int hsw_pcm_remove(struct snd_soc_platform *platform) |
@@ -791,9 +795,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform) | |||
791 | 795 | ||
792 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 796 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
793 | if (hsw_dais[i].playback.channels_min) | 797 | if (hsw_dais[i].playback.channels_min) |
794 | kfree(priv_data->pcm_pg[i][0]); | 798 | snd_dma_free_pages(&priv_data->dmab[i][0]); |
795 | if (hsw_dais[i].capture.channels_min) | 799 | if (hsw_dais[i].capture.channels_min) |
796 | kfree(priv_data->pcm_pg[i][1]); | 800 | snd_dma_free_pages(&priv_data->dmab[i][1]); |
797 | } | 801 | } |
798 | 802 | ||
799 | return 0; | 803 | return 0; |