ASoC: Intel fixes for v3.15
This is a relatively large batch of fixes for the newly added Haswell/Baytrail drivers from Intel. It's a bit larger than is good for this point in the cycle but it's all for a newly added driver so not so worrying as it might otherwise be. Some of it's integration problems, some of it's the sort of problem usually turned up in stress tests. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTc1YrAAoJELSic+t+oim9losP/0I50EKB6hrEugvFrNT+vBkR OQxhcj+WGgIguVQNqaHPBr3rQ1iGG54C5Yf1KDSi2jNIjkHSTIJ1bT2QB40rmclT 14V6LZJL481TadcKcjLux1jgmaMvNO5Fa1gqYdLLVZFUYP/yTCLhqYrVIDO7NC6M VCKtZ965l4u6TMJACTdz9MzCbAwlhb7OTpgxIiyVQlE4SPq2D7M8W9IceLjiDzGg rviGK7MejMxc2b4i2vJGi4msaqK8aazDmMhoqrI+HZr/6pZgWkvKJ2S/zZf8AdEH 6KfEQ8vPU/ag8M4UoH72JJtn1gsjphkEY8GyNWCvP7fIXnpcYB34c/cyaaMQ6lGN fGPfwQpbNobx3sJsPMRj21kFgy61rXM2PcbA4QEhPniHd6UlVPUgjkxBNE2YVM3d 0+tWtgzWVT10F10fcKIkw00/gDohBK+4rViAu0VK5Ml90F0eYLeITWYFVyjmU52f 7Q+0Duwm65LsA4hqFKcH5lRbk6IM29yRte/wGYY8mLWODADO0+cU6WmVRDHTlRFo 35HidtfY8EGcU+rS24XyGd0+GRoO+nghzKTckoD3z9OCPilePkMb/dD5vC7NvmMO 5Q15VbxmJgsus0aTDOPD634XoVTlQ/ESBA6bj5APylZorNKyANorJBphn4rBfZV+ GXtzzjFrllDCOpKtjDzB =ROtF -----END PGP SIGNATURE----- Merge tag 'asoc-v3.15-rc5-intel' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus ASoC: Intel fixes for v3.15 This is a relatively large batch of fixes for the newly added Haswell/Baytrail drivers from Intel. It's a bit larger than is good for this point in the cycle but it's all for a newly added driver so not so worrying as it might otherwise be. Some of it's integration problems, some of it's the sort of problem usually turned up in stress tests.
This commit is contained in:
Коммит
ff2354bc6e
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -169,6 +169,7 @@ struct sst_pdata {
|
|||
u32 dma_base;
|
||||
u32 dma_size;
|
||||
int dma_engine;
|
||||
struct device *dma_dev;
|
||||
|
||||
/* DSP */
|
||||
u32 id;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -1159,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;
|
||||
|
@ -1172,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;
|
||||
}
|
||||
|
@ -1180,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)
|
||||
|
@ -1201,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;
|
||||
}
|
||||
|
@ -1538,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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче