diff options
Diffstat (limited to 'sound/soc/intel')
| -rw-r--r-- | sound/soc/intel/sst-acpi.c | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst-baytrail-dsp.c | 2 | ||||
| -rw-r--r-- | sound/soc/intel/sst-baytrail-ipc.c | 8 | ||||
| -rw-r--r-- | sound/soc/intel/sst-dsp-priv.h | 3 | ||||
| -rw-r--r-- | sound/soc/intel/sst-dsp.c | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst-dsp.h | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst-firmware.c | 25 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-dsp.c | 4 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-ipc.c | 38 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-ipc.h | 4 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-pcm.c | 107 | 
11 files changed, 131 insertions, 63 deletions
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index 5d06eecb6198..18aee77f8d4a 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c @@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev)  	sst_pdata = &sst_acpi->sst_pdata;  	sst_pdata->id = desc->sst_id; +	sst_pdata->dma_dev = dev;  	sst_acpi->desc = desc;  	sst_acpi->mach = mach; diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c index a50bf7fc0e3a..adf0aca5aca6 100644 --- a/sound/soc/intel/sst-baytrail-dsp.c +++ b/sound/soc/intel/sst-baytrail-dsp.c @@ -324,7 +324,7 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)  	memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,  	       &pdata->fw_base, sizeof(u32)); -	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); +	ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));  	if (ret)  		return ret; diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index d0eaeee21be4..0d31dbbf4806 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,  	void *data)  {  	struct sst_byt_stream *stream; +	struct sst_dsp *sst = byt->dsp; +	unsigned long flags;  	stream = kzalloc(sizeof(*stream), GFP_KERNEL);  	if (stream == NULL)  		return NULL; +	spin_lock_irqsave(&sst->spinlock, flags);  	list_add(&stream->node, &byt->stream_list);  	stream->notify_position = notify_position;  	stream->pdata = data;  	stream->byt = byt;  	stream->str_id = id; +	spin_unlock_irqrestore(&sst->spinlock, flags);  	return stream;  } @@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)  {  	u64 header;  	int ret = 0; +	struct sst_dsp *sst = byt->dsp; +	unsigned long flags;  	if (!stream->commited)  		goto out; @@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)  	stream->commited = false;  out: +	spin_lock_irqsave(&sst->spinlock, flags);  	list_del(&stream->node);  	kfree(stream); +	spin_unlock_irqrestore(&sst->spinlock, flags);  	return ret;  } diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index fe8e81aad646..401213455497 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h @@ -136,7 +136,7 @@ struct sst_module_data {  	enum sst_data_type data_type;	/* type of module data */  	u32 size;		/* size in bytes */ -	u32 offset;		/* offset in FW file */ +	int32_t offset;		/* offset in FW file */  	u32 data_offset;	/* offset in ADSP memory space */  	void *data;		/* module data */  }; @@ -228,6 +228,7 @@ struct sst_dsp {  	spinlock_t spinlock;	/* IPC locking */  	struct mutex mutex;	/* DSP FW lock */  	struct device *dev; +	struct device *dma_dev;  	void *thread_context;  	int irq;  	u32 id; diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 0c129fd85ecf..0b715b20a2d7 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c @@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,  	spin_lock_init(&sst->spinlock);  	mutex_init(&sst->mutex);  	sst->dev = dev; +	sst->dma_dev = pdata->dma_dev;  	sst->thread_context = sst_dev->thread_context;  	sst->sst_dev = sst_dev;  	sst->id = pdata->id; diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index 74052b59485c..e44423be66c4 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h @@ -169,6 +169,7 @@ struct sst_pdata {  	u32 dma_base;  	u32 dma_size;  	int dma_engine; +	struct device *dma_dev;  	/* DSP */  	u32 id; diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index f7687107cf7f..928f228c38e7 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -57,14 +57,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,  	sst_fw->private = private;  	sst_fw->size = fw->size; -	err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32)); -	if (err < 0) { -		kfree(sst_fw); -		return NULL; -	} -  	/* allocate DMA buffer to store FW data */ -	sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size, +	sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size,  				&sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);  	if (!sst_fw->dma_buf) {  		dev_err(dsp->dev, "error: DMA alloc failed\n"); @@ -106,7 +100,7 @@ void sst_fw_free(struct sst_fw *sst_fw)  	list_del(&sst_fw->list);  	mutex_unlock(&dsp->mutex); -	dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, +	dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,  			sst_fw->dmable_fw_paddr);  	kfree(sst_fw);  } @@ -202,6 +196,9 @@ static int block_alloc_contiguous(struct sst_module *module,  		size -= block->size;  	} +	list_for_each_entry(block, &tmp, list) +		list_add(&block->module_list, &module->block_list); +  	list_splice(&tmp, &dsp->used_block_list);  	return 0;  } @@ -247,8 +244,7 @@ static int block_alloc(struct sst_module *module,  		/* do we span > 1 blocks */  		if (data->size > block->size) {  			ret = block_alloc_contiguous(module, data, -				block->offset + block->size, -				data->size - block->size); +				block->offset, data->size);  			if (ret == 0)  				return ret;  		} @@ -344,7 +340,7 @@ static int block_alloc_fixed(struct sst_module *module,  			err = block_alloc_contiguous(module, data,  				block->offset + block->size, -				data->size - block->size + data->offset - block->offset); +				data->size - block->size);  			if (err < 0)  				return -ENOMEM; @@ -371,15 +367,10 @@ static int block_alloc_fixed(struct sst_module *module,  		if (data->offset >= block->offset && data->offset < block_end) {  			err = block_alloc_contiguous(module, data, -				block->offset + block->size, -				data->size - block->size); +				block->offset, data->size);  			if (err < 0)  				return -ENOMEM; -			/* add block */ -			block->data_type = data->data_type; -			list_move(&block->list, &dsp->used_block_list); -			list_add(&block->module_list, &module->block_list);  			return 0;  		} diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index f5ebf36af889..535f517629fd 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)  	int ret = -ENODEV, i, j, region_count;  	u32 offset, size; -	dev = sst->dev; +	dev = sst->dma_dev;  	switch (sst->id) {  	case SST_DEV_ID_LYNX_POINT: @@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)  		return ret;  	} -	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); +	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));  	if (ret)  		return ret; diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index f46bb4ddde6f..e7996b39a484 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -617,7 +617,7 @@ static void hsw_notification_work(struct work_struct *work)  	case IPC_POSITION_CHANGED:  		trace_ipc_notification("DSP stream position changed for",  			stream->reply.stream_hw_id); -		sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos)); +		sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos));  		if (stream->notify_position)  			stream->notify_position(stream, stream->pdata); @@ -991,7 +991,8 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream  		return -EINVAL;  	sst_dsp_read(hsw->dsp, volume, -		stream->reply.volume_register_address[channel], sizeof(volume)); +		stream->reply.volume_register_address[channel], +		sizeof(*volume));  	return 0;  } @@ -1158,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,  	void *data)  {  	struct sst_hsw_stream *stream; +	struct sst_dsp *sst = hsw->dsp; +	unsigned long flags;  	stream = kzalloc(sizeof(*stream), GFP_KERNEL);  	if (stream == NULL)  		return NULL; +	spin_lock_irqsave(&sst->spinlock, flags);  	list_add(&stream->node, &hsw->stream_list);  	stream->notify_position = notify_position;  	stream->pdata = data; @@ -1171,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,  	/* work to process notification messages */  	INIT_WORK(&stream->notify_work, hsw_notification_work); +	spin_unlock_irqrestore(&sst->spinlock, flags);  	return stream;  } @@ -1179,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)  {  	u32 header;  	int ret = 0; +	struct sst_dsp *sst = hsw->dsp; +	unsigned long flags;  	/* dont free DSP streams that are not commited */  	if (!stream->commited) @@ -1200,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)  	trace_hsw_stream_free_req(stream, &stream->free_req);  out: +	cancel_work_sync(&stream->notify_work); +	spin_lock_irqsave(&sst->spinlock, flags);  	list_del(&stream->node);  	kfree(stream); +	spin_unlock_irqrestore(&sst->spinlock, flags);  	return ret;  } @@ -1537,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)  }  /* Stream pointer positions */ -int sst_hsw_get_dsp_position(struct sst_hsw *hsw, +u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,  	struct sst_hsw_stream *stream)  { -	return stream->rpos.position; +	u32 rpos; + +	sst_dsp_read(hsw->dsp, &rpos, +		stream->reply.read_position_register_address, sizeof(rpos)); + +	return rpos; +} + +/* Stream presentation (monotonic) positions */ +u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, +	struct sst_hsw_stream *stream) +{ +	u64 ppos; + +	sst_dsp_read(hsw->dsp, &ppos, +		stream->reply.presentation_position_register_address, +		sizeof(ppos)); + +	return ppos;  }  int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, @@ -1609,7 +1637,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw,  	trace_ipc_request("PM enter Dx state", state);  	ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), -		dx, sizeof(dx)); +		dx, sizeof(*dx));  	if (ret < 0) {  		dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);  		return ret; diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index d517929ccc38..2ac194a6d04b 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,  	struct sst_hsw_stream *stream, u32 *position);  int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,  	struct sst_hsw_stream *stream, u32 stage_id, u32 position); -int sst_hsw_get_dsp_position(struct sst_hsw *hsw, +u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, +	struct sst_hsw_stream *stream); +u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,  	struct sst_hsw_stream *stream);  /* HW port config */ diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 0a32dd13a23d..9d5f64a583a3 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -99,6 +99,7 @@ struct hsw_pcm_data {  	struct snd_compr_stream *cstream;  	unsigned int wpos;  	struct mutex mutex; +	bool allocated;  };  /* private data for the driver */ @@ -107,12 +108,14 @@ struct hsw_priv_data {  	struct sst_hsw *hsw;  	/* page tables */ -	unsigned char *pcm_pg[HSW_PCM_COUNT][2]; +	struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];  	/* DAI data */  	struct hsw_pcm_data pcm[HSW_PCM_COUNT];  }; +static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); +  static inline u32 hsw_mixer_to_ipc(unsigned int value)  {  	if (value >= ARRAY_SIZE(volume_map)) @@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {  };  /* Create DMA buffer page table for DSP */ -static int create_adsp_page_table(struct hsw_priv_data *pdata, -	struct snd_soc_pcm_runtime *rtd, -	unsigned char *dma_area, size_t size, int pcm, int stream) +static int create_adsp_page_table(struct snd_pcm_substream *substream, +	struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd, +	unsigned char *dma_area, size_t size, int pcm)  { -	int i, pages; +	struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); +	int i, pages, stream = substream->stream; -	if (size % PAGE_SIZE) -		pages = (size / PAGE_SIZE) + 1; -	else -		pages = size / PAGE_SIZE; +	pages = snd_sgbuf_aligned_pages(size);  	dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",  		dma_area, size, pages);  	for (i = 0; i < pages; i++) {  		u32 idx = (((i << 2) + i)) >> 1; -		u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; +		u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;  		u32 *pg_table;  		dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); -		pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); +		pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);  		if (i & 1)  			*pg_table |= (pfn << 4); @@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,  	struct sst_hsw *hsw = pdata->hsw;  	struct sst_module *module_data;  	struct sst_dsp *dsp; +	struct snd_dma_buffer *dmab;  	enum sst_hsw_stream_type stream_type;  	enum sst_hsw_stream_path_id path_id;  	u32 rate, bits, map, pages, module_id;  	u8 channels;  	int ret; +	/* check if we are being called a subsequent time */ +	if (pcm_data->allocated) { +		ret = sst_hsw_stream_reset(hsw, pcm_data->stream); +		if (ret < 0) +			dev_dbg(rtd->dev, "error: reset stream failed %d\n", +				ret); + +		ret = sst_hsw_stream_free(hsw, pcm_data->stream); +		if (ret < 0) { +			dev_dbg(rtd->dev, "error: free stream failed %d\n", +				ret); +			return ret; +		} +		pcm_data->allocated = false; + +		pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id, +			hsw_notify_pointer, pcm_data); +		if (pcm_data->stream == NULL) { +			dev_err(rtd->dev, "error: failed to create stream\n"); +			return -EINVAL; +		} +	} +  	/* stream direction */  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  		path_id = SST_HSW_STREAM_PATH_SSP0_OUT; @@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,  		return ret;  	} -	ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, -		runtime->dma_bytes, rtd->cpu_dai->id, substream->stream); +	dmab = snd_pcm_get_dma_buf(substream); + +	ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area, +		runtime->dma_bytes, rtd->cpu_dai->id);  	if (ret < 0)  		return ret; @@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,  		pages = runtime->dma_bytes / PAGE_SIZE;  	ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, -		virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), +		pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,  		pages, runtime->dma_bytes, 0, -		(u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); +		snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);  	if (ret < 0) {  		dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);  		return ret; @@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,  		dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);  		return ret;  	} +	pcm_data->allocated = true;  	ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);  	if (ret < 0) @@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)  	struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);  	struct sst_hsw *hsw = pdata->hsw;  	snd_pcm_uframes_t offset; +	uint64_t ppos; +	u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); -	offset = bytes_to_frames(runtime, -		sst_hsw_get_dsp_position(hsw, pcm_data->stream)); +	offset = bytes_to_frames(runtime, position); +	ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); -	dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", -		frames_to_bytes(runtime, (u32)offset)); +	dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", +		position, ppos);  	return offset;  } @@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)  		dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);  		goto out;  	} +	pcm_data->allocated = 0;  	pcm_data->stream = NULL;  out: @@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = {  	.hw_free	= hsw_pcm_hw_free,  	.trigger	= hsw_pcm_trigger,  	.pointer	= hsw_pcm_pointer, -	.mmap		= snd_pcm_lib_default_mmap, +	.page		= snd_pcm_sgbuf_ops_page,  };  static void hsw_pcm_free(struct snd_pcm *pcm) @@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm)  static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)  {  	struct snd_pcm *pcm = rtd->pcm; +	struct snd_soc_platform *platform = rtd->platform; +	struct sst_pdata *pdata = dev_get_platdata(platform->dev); +	struct device *dev = pdata->dma_dev;  	int ret = 0; -	ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); -	if (ret) -		return ret; -  	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||  			pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {  		ret = snd_pcm_lib_preallocate_pages_for_all(pcm, -			SNDRV_DMA_TYPE_DEV, -			rtd->card->dev, +			SNDRV_DMA_TYPE_DEV_SG, +			dev,  			hsw_pcm_hardware.buffer_bytes_max,  			hsw_pcm_hardware.buffer_bytes_max);  		if (ret) { @@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)  {  	struct sst_pdata *pdata = dev_get_platdata(platform->dev);  	struct hsw_priv_data *priv_data; -	int i; +	struct device *dma_dev; +	int i, ret = 0;  	if (!pdata)  		return -ENODEV; +	dma_dev = pdata->dma_dev; +  	priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);  	priv_data->hsw = pdata->dsp;  	snd_soc_platform_set_drvdata(platform, priv_data); @@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)  		/* playback */  		if (hsw_dais[i].playback.channels_min) { -			priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); -			if (priv_data->pcm_pg[i][0] == NULL) +			ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, +				PAGE_SIZE, &priv_data->dmab[i][0]); +			if (ret < 0)  				goto err;  		}  		/* capture */  		if (hsw_dais[i].capture.channels_min) { -			priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); -			if (priv_data->pcm_pg[i][1] == NULL) +			ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, +				PAGE_SIZE, &priv_data->dmab[i][1]); +			if (ret < 0)  				goto err;  		}  	} @@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)  err:  	for (;i >= 0; i--) {  		if (hsw_dais[i].playback.channels_min) -			kfree(priv_data->pcm_pg[i][0]); +			snd_dma_free_pages(&priv_data->dmab[i][0]);  		if (hsw_dais[i].capture.channels_min) -			kfree(priv_data->pcm_pg[i][1]); +			snd_dma_free_pages(&priv_data->dmab[i][1]);  	} -	return -ENOMEM; +	return ret;  }  static int hsw_pcm_remove(struct snd_soc_platform *platform) @@ -791,9 +826,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)  	for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {  		if (hsw_dais[i].playback.channels_min) -			kfree(priv_data->pcm_pg[i][0]); +			snd_dma_free_pages(&priv_data->dmab[i][0]);  		if (hsw_dais[i].capture.channels_min) -			kfree(priv_data->pcm_pg[i][1]); +			snd_dma_free_pages(&priv_data->dmab[i][1]);  	}  	return 0;  | 

