aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorLiam Girdwood <liam.r.girdwood@linux.intel.com>2014-05-02 11:56:30 -0400
committerMark Brown <broonie@linaro.org>2014-05-02 12:53:01 -0400
commit0b708c87f66a15190fb43661c2320fd48c4dc6c8 (patch)
tree2f8f4c323abdb2d39951be86f361219b74ecacd9 /sound/soc
parent84fbdd58614e35108ece5c79ada33443dbcdaf37 (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.c58
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 */
276static int create_adsp_page_table(struct hsw_priv_data *pdata, 276static 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
627static void hsw_pcm_free(struct snd_pcm *pcm) 628static 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)
776err: 780err:
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
786static int hsw_pcm_remove(struct snd_soc_platform *platform) 790static 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;