ASoC: msm8974: fall back to have AFE port started at prepare
After upgrading to kernel 3.4, there is 5 second delay
at the closing of PCM playback. The delay is due to missing
EOS from QDSP6 audio session manager causing pcm close function
of PCM platform driver to wait for 5 seconds. The root cause
for missing EOS is that ALSA dynmic PCM shutdown sequence has
changed. Now, trigger stop is called on the back-end DAI-LINK.
Furthermore, back-end trigger stop is called before front-end
trigger stop. Since sink stops rendering data, data at source
will never get consumed. EOS event will not arrive. As trigger
operation has to be atomic, it is very difficult to guarantee
sequence on shutting down various modules in QDSP6. The decision
is to abandon starting and stopping QDSP6 AFE port in trigger
function. This decision is considered acceptable as playback
and capture over SLIMBUS is no longer subject to strict sequence
which Q6 AFE port must be started after CODEC configuration.
Change-Id: Ief351168b08d5cca0a76405834cf3d6aa14a3941
Signed-off-by: Phani Kumar Uppalapati <phanik@codeaurora.org>
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index b1ed9a4..8ccc9f4 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -92,7 +92,7 @@
int afe_unregister_get_events(u16 port_id);
int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes);
int afe_rt_proxy_port_read(u32 buf_addr_p, u32 mem_map_handle, int bytes);
-int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate);
int afe_port_stop_nowait(int port_id);
int afe_apply_gain(u16 port_id, u16 gain);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 485569b..3eab972 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -400,70 +400,23 @@
int rc = 0;
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- /* PORT START should be set if prepare called in active state */
- rc = afe_q6_interface_prepare();
+ switch (dai->id) {
+ case VOICE_PLAYBACK_TX:
+ case VOICE_RECORD_TX:
+ case VOICE_RECORD_RX:
+ rc = afe_start_pseudo_port(dai->id);
+ default:
+ rc = afe_port_start(dai->id, &dai_data->port_config,
+ dai_data->rate);
+ }
+
if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to open AFE APR\n");
- }
- return rc;
-}
-
-static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
- int rc = 0;
-
- /*
- * Start/stop port without waiting for Q6 AFE response. Need to have
- * native q6 AFE driver propagates AFE response in order to handle
- * port start/stop command error properly if error does arise.
- */
- pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
- __func__, dai->id, cmd, *dai_data->status_mask);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- switch (dai->id) {
- case VOICE_PLAYBACK_TX:
- case VOICE_RECORD_TX:
- case VOICE_RECORD_RX:
- afe_pseudo_port_start_nowait(dai->id);
- break;
- default:
- afe_port_start_nowait(dai->id,
- &dai_data->port_config, dai_data->rate);
- break;
- }
+ dev_err(dai->dev, "fail to open AFE port %x\n",
+ dai->id);
+ else
set_bit(STATUS_PORT_STARTED,
dai_data->status_mask);
- }
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- switch (dai->id) {
- case VOICE_PLAYBACK_TX:
- case VOICE_RECORD_TX:
- case VOICE_RECORD_RX:
- afe_pseudo_port_stop_nowait(dai->id);
- break;
- default:
- afe_port_stop_nowait(dai->id);
- break;
- }
- clear_bit(STATUS_PORT_STARTED,
- dai_data->status_mask);
- }
- break;
-
- default:
- rc = -EINVAL;
}
-
return rc;
}
@@ -799,7 +752,6 @@
static struct snd_soc_dai_ops msm_dai_q6_ops = {
.prepare = msm_dai_q6_prepare,
- .trigger = msm_dai_q6_trigger,
.hw_params = msm_dai_q6_hw_params,
.shutdown = msm_dai_q6_shutdown,
.set_fmt = msm_dai_q6_set_fmt,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 2e58e1b..0b25545 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -30,6 +30,7 @@
atomic_t state;
atomic_t status;
wait_queue_head_t wait[AFE_MAX_PORTS];
+ struct task_struct *task;
void (*tx_cb) (uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv);
void (*rx_cb) (uint32_t opcode,
@@ -58,6 +59,9 @@
atomic_set(&this_afe.state, 0);
this_afe.apr = NULL;
}
+ /* send info to user */
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
return 0;
}
pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
@@ -248,7 +252,7 @@
afe_send_cal_block(RX_CAL, port_id);
}
-int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate) /* This function is no blocking */
{
struct afe_port_cmd_device_start start;
@@ -274,8 +278,9 @@
port_id = VIRTUAL_ID_TO_PORTID(port_id);
ret = afe_q6_interface_prepare();
- if (ret != 0)
+ if (IS_ERR_VALUE(ret))
return ret;
+
if (q6audio_validate_port(port_id) < 0) {
pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
port_id);
@@ -338,6 +343,8 @@
config.port = *afe_config;
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
if (ret < 0) {
pr_err("%s: AFE enable for port %d failed\n", __func__,
@@ -345,7 +352,20 @@
ret = -EINVAL;
goto fail_cmd;
}
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
/* send AFE cal */
afe_send_cal(port_id);
@@ -360,6 +380,7 @@
pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
__func__, start.hdr.opcode, start.port_id);
+ atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
if (IS_ERR_VALUE(ret)) {
@@ -369,6 +390,21 @@
goto fail_cmd;
}
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ pr_err("%s: wait_event timeout PORT START\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (this_afe.task != current)
+ this_afe.task = current;
+
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
+
return 0;
fail_cmd:
@@ -506,8 +542,7 @@
config.pdata.param_size = sizeof(config.port);
config.port = *afe_config;
- pr_debug("%s: param PL size=%d iparam_size[%d][%d %d %d %d]"
- " param_id[%x]\n",
+ pr_debug("%s: param PL size=%d iparam_size[%d][%d %d %d %d] param_id[%x]\n",
__func__, config.param.payload_size, config.pdata.param_size,
sizeof(config), sizeof(config.param), sizeof(config.port),
sizeof(struct apr_hdr), config.pdata.param_id);
@@ -653,8 +688,8 @@
/* RX ports numbers are even .TX ports numbers are odd. */
if (port_id % 2 == 0) {
- pr_err("%s: Failed : afe loopback gain only for TX ports."
- " port_id %d\n", __func__, port_id);
+ pr_err("%s: Failed : afe loopback gain only for TX ports. port_id %d\n",
+ __func__, port_id);
ret = -EINVAL;
goto fail_cmd;
}
@@ -1319,7 +1354,7 @@
else
base = 10;
- if (strict_strtoul(token, base, ¶m1[cnt]) != 0)
+ if (kstrtoul(token, base, ¶m1[cnt]) != 0)
return -EINVAL;
token = strsep(&buf, " ");
@@ -1389,8 +1424,7 @@
}
if (param[1] < 0 || param[1] > 100) {
- pr_err("%s: Error, volume shoud be 0 to 100"
- " percentage param = %lu\n",
+ pr_err("%s: Error, volume shoud be 0 to 100 percentage param = %lu\n",
__func__, param[1]);
rc = -EINVAL;
goto afe_error;