From patchwork Fri Oct 28 15:32:19 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 79959 Delivered-To: patch@linaro.org Received: by 10.140.97.247 with SMTP id m110csp1238174qge; Fri, 28 Oct 2016 08:33:01 -0700 (PDT) X-Received: by 10.98.9.67 with SMTP id e64mr26321623pfd.74.1477668781219; Fri, 28 Oct 2016 08:33:01 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 137si14140720pfw.94.2016.10.28.08.33.00; Fri, 28 Oct 2016 08:33:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760720AbcJ1Pc4 (ORCPT + 27 others); Fri, 28 Oct 2016 11:32:56 -0400 Received: from mail-wm0-f42.google.com ([74.125.82.42]:38304 "EHLO mail-wm0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965235AbcJ1Pc2 (ORCPT ); Fri, 28 Oct 2016 11:32:28 -0400 Received: by mail-wm0-f42.google.com with SMTP id n67so122084992wme.1 for ; Fri, 28 Oct 2016 08:32:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=2A4uZoY4JfgLt8Sgcf4OcfzuDZvGexFHN7Xg+27krQU=; b=L/x8moGZgjx5aRz3F9myw1WxQvJmnxuHHaNLPwD9/MI6UcbV/Z3Gr/F8vsH1tq7TQx 99LkqxBQb1yN0XpNE11w+lw89IBrXn3ZkGex/SwyCMJwkMh0JmIrogASLMmmEwQGMj44 XOPWU7Nb+vegsJMi0svzJCH3x65M0fm+woS4Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=2A4uZoY4JfgLt8Sgcf4OcfzuDZvGexFHN7Xg+27krQU=; b=bDe3hHnpOIsyStDlH1qZHayhVkZo/Iviab7mjcdNUbn8a0ex4LtbAhPCOdYK+HQY/C ozcHzBoimqfZHvukWR5p+1S5UkGow1Tdq8XIDMo1XbFFIWpPggBWfSr4hvhGJFzxEKMq asBTHGlsKgjL8OxUISJLbcfRaUdXadQnpQqkd7fMRTsdptEDENdtOoQGJGPSwSuFPhFA 3RfhW5tclhdAzLnnYTXH4q2a2IsduNPsdIvWoGB+GRuQEPKCXuOxJhctZH7ad9V5WUZH ScLdr33i2fUf9pUJkVxhb8AjJ9cjrLNbCz/MctDtshX5nSUhmsf4K7DF0vqfDtfJoFTJ ByoA== X-Gm-Message-State: ABUngvc5TRTki+6vtIzoyehfyD32eApAkELZJdbVCJEDh5jmif4+t1euUG4Ao5Gu2gjUKQBy X-Received: by 10.194.103.165 with SMTP id fx5mr11861796wjb.188.1477668746635; Fri, 28 Oct 2016 08:32:26 -0700 (PDT) Received: from localhost.localdomain (host-2-98-102-117.as13285.net. [2.98.102.117]) by smtp.gmail.com with ESMTPSA id za1sm14708033wjb.8.2016.10.28.08.32.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 28 Oct 2016 08:32:26 -0700 (PDT) From: Srinivas Kandagatla To: Mark Brown , alsa-devel@alsa-project.org Cc: Banajit Goswami , Liam Girdwood , Jaroslav Kysela , Takashi Iwai , linux-kernel@vger.kernel.org, Kenneth Westfield , Kuninori Morimoto , Srinivas Kandagatla Subject: [PATCH 2/3] ASoC: lpass-platform: Fix broken pcm data usage Date: Fri, 28 Oct 2016 16:32:19 +0100 Message-Id: <1477668740-30389-3-git-send-email-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1477668740-30389-1-git-send-email-srinivas.kandagatla@linaro.org> References: <1477668740-30389-1-git-send-email-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch fixes lpass-platform driver which was broken in v4.9-rc1. lpass_pcm_data data structure holds information specific to stream. Holding a single private pointer to it in global lpass_data will not work, because it would be overwritten by for each pcm instance. This code was breaking playback when we have both playback and capture pcm streams, as playback settings are over written by capture settings. Fix this by moving channel allocation logic out of pcm_new to pcm_open so that we can store the stream specific information private_data of snd_pcm_runtime. Fixes: 6adcbdcd4b6e ("ASoC: lpass-platform: don't use snd_soc_pcm_set_drvdata()") Signed-off-by: Srinivas Kandagatla --- sound/soc/qcom/lpass-platform.c | 151 ++++++++++++++++++---------------------- sound/soc/qcom/lpass.h | 1 - 2 files changed, 67 insertions(+), 85 deletions(-) -- 2.10.1 Acked-by: Kenneth Westfield diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 2570c96..4554cae 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -60,7 +60,36 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - int ret; + struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_variant *v = drvdata->variant; + int ret, dir = substream->stream; + struct lpass_pcm_data *data; + + data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->i2s_port = cpu_dai->driver->id; + runtime->private_data = data; + + if (v->alloc_dma_channel) + data->dma_ch = v->alloc_dma_channel(drvdata, dir); + if (data->dma_ch < 0) + return data->dma_ch; + + drvdata->substream[data->dma_ch] = substream; + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_DMACTL_REG(v, data->dma_ch, dir), 0); + if (ret) { + dev_err(soc_runtime->dev, + "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + return ret; + } + snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); @@ -79,13 +108,32 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) return 0; } +static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_variant *v = drvdata->variant; + struct lpass_pcm_data *data; + + data = runtime->private_data; + v = drvdata->variant; + drvdata->substream[data->dma_ch] = NULL; + if (v->free_dma_channel) + v->free_dma_channel(drvdata, data->dma_ch); + + return 0; +} + static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); @@ -175,7 +223,8 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; unsigned int reg; int ret; @@ -195,7 +244,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; @@ -246,7 +296,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; @@ -319,7 +370,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; int ret, ch, dir = substream->stream; @@ -357,6 +409,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream, static const struct snd_pcm_ops lpass_platform_pcm_ops = { .open = lpass_platform_pcmops_open, + .close = lpass_platform_pcmops_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = lpass_platform_pcmops_hw_params, .hw_free = lpass_platform_pcmops_hw_free, @@ -453,115 +506,45 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) { struct snd_pcm *pcm = soc_runtime->pcm; struct snd_pcm_substream *psubstream, *csubstream; - struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; - struct lpass_data *drvdata = - snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_variant *v = drvdata->variant; int ret = -EINVAL; - struct lpass_pcm_data *data; size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; - data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->i2s_port = cpu_dai->driver->id; - drvdata->private_data = data; - psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (psubstream) { - if (v->alloc_dma_channel) - data->dma_ch = v->alloc_dma_channel(drvdata, - SNDRV_PCM_STREAM_PLAYBACK); - - if (data->dma_ch < 0) - return data->dma_ch; - - drvdata->substream[data->dma_ch] = psubstream; - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, soc_runtime->platform->dev, size, &psubstream->dma_buffer); - if (ret) - goto playback_alloc_err; - - ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, data->dma_ch), 0); if (ret) { - dev_err(soc_runtime->dev, - "%s() error writing to rdmactl reg: %d\n", - __func__, ret); - goto capture_alloc_err; + dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); + return ret; } } csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; if (csubstream) { - if (v->alloc_dma_channel) - data->dma_ch = v->alloc_dma_channel(drvdata, - SNDRV_PCM_STREAM_CAPTURE); - - if (data->dma_ch < 0) { - ret = data->dma_ch; - goto capture_alloc_err; - } - - drvdata->substream[data->dma_ch] = csubstream; - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, soc_runtime->platform->dev, size, &csubstream->dma_buffer); - if (ret) - goto capture_alloc_err; - - ret = regmap_write(drvdata->lpaif_map, - LPAIF_WRDMACTL_REG(v, data->dma_ch), 0); if (ret) { - dev_err(soc_runtime->dev, - "%s() error writing to wrdmactl reg: %d\n", - __func__, ret); - goto capture_reg_err; + dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); + if (psubstream) + snd_dma_free_pages(&psubstream->dma_buffer); + return ret; } + } return 0; - -capture_reg_err: - if (csubstream) - snd_dma_free_pages(&csubstream->dma_buffer); - -capture_alloc_err: - if (psubstream) - snd_dma_free_pages(&psubstream->dma_buffer); - - playback_alloc_err: - dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); - - return ret; } static void lpass_platform_pcm_free(struct snd_pcm *pcm) { - struct snd_soc_pcm_runtime *rt; - struct lpass_data *drvdata; - struct lpass_pcm_data *data; - struct lpass_variant *v; struct snd_pcm_substream *substream; - int ch, i; + int i; for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { substream = pcm->streams[i].substream; if (substream) { - rt = substream->private_data; - drvdata = snd_soc_platform_get_drvdata(rt->platform); - data = drvdata->private_data; - - ch = data->dma_ch; - v = drvdata->variant; - drvdata->substream[ch] = NULL; - if (v->free_dma_channel) - v->free_dma_channel(drvdata, ch); - snd_dma_free_pages(&substream->dma_buffer); substream->dma_buffer.area = NULL; substream->dma_buffer.addr = 0; diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 35b3cea..924971b 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -59,7 +59,6 @@ struct lpass_data { struct clk *pcnoc_mport_clk; struct clk *pcnoc_sway_clk; - void *private_data; }; /* Vairant data per each SOC */