Loading sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +112 −18 Original line number Diff line number Diff line Loading @@ -114,6 +114,8 @@ struct msm_compr_audio { uint32_t cmd_ack; uint32_t cmd_interrupt; uint32_t drain_ready; uint32_t stream_available; uint32_t next_stream; struct msm_compr_gapless_state gapless_state; Loading @@ -129,6 +131,7 @@ struct msm_compr_audio { wait_queue_head_t drain_wait; wait_queue_head_t flush_wait; wait_queue_head_t close_wait; wait_queue_head_t wait_for_stream_avail; spinlock_t lock; }; Loading Loading @@ -335,6 +338,8 @@ static void compr_event_handler(uint32_t opcode, prtd->gapless_state.stream_opened[stream_id] = 0; prtd->gapless_state.set_next_stream_id = false; } if (prtd->gapless_state.gapless_transition) prtd->gapless_state.gapless_transition = 0; spin_unlock(&prtd->lock); break; case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY: Loading Loading @@ -379,6 +384,17 @@ static void compr_event_handler(uint32_t opcode, break; case ASM_STREAM_CMD_CLOSE: pr_debug("ASM_DATA_CMD_CLOSE\n"); /* * wakeup wait for stream avail on stream 3 * after stream 1 ends. */ if (prtd->next_stream) { pr_debug("%s:CLOSE:wakeup wait for stream\n", __func__); prtd->stream_available = 1; wake_up(&prtd->wait_for_stream_avail); prtd->next_stream = 0; } if (atomic_read(&prtd->close) && atomic_read(&prtd->wait_on_close)) { prtd->cmd_ack = 1; Loading Loading @@ -705,6 +721,7 @@ static int msm_compr_open(struct snd_compr_stream *cstream) prtd->last_buffer = 0; prtd->first_buffer = 1; prtd->partial_drain_delay = 0; prtd->next_stream = 0; memset(&prtd->gapless_state, 0, sizeof(struct msm_compr_gapless_state)); /* * Update the use_dsp_gapless_mode from gapless struture with the value Loading @@ -728,6 +745,7 @@ static int msm_compr_open(struct snd_compr_stream *cstream) init_waitqueue_head(&prtd->drain_wait); init_waitqueue_head(&prtd->flush_wait); init_waitqueue_head(&prtd->close_wait); init_waitqueue_head(&prtd->wait_for_stream_avail); runtime->private_data = prtd; populate_codec_list(prtd); Loading Loading @@ -758,19 +776,6 @@ static int msm_compr_free(struct snd_compr_stream *cstream) unsigned long flags; pr_debug("%s\n", __func__); pdata->cstream[soc_prtd->dai_link->be_id] = NULL; if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (atomic_read(&pdata->audio_ocmem_req) > 1) atomic_dec(&pdata->audio_ocmem_req); else if (atomic_cmpxchg(&pdata->audio_ocmem_req, 1, 0)) audio_ocmem_process_req(AUDIO, false); msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); } pr_debug("%s: ocmem_req: %d\n", __func__, atomic_read(&pdata->audio_ocmem_req)); if (atomic_read(&prtd->eos)) { ret = wait_event_timeout(prtd->eos_wait, Loading @@ -791,16 +796,30 @@ static int msm_compr_free(struct snd_compr_stream *cstream) stream_id = ac->stream_id; if (prtd->gapless_state.stream_opened[stream_id^1]) { spin_unlock_irqrestore(&prtd->lock, flags); pr_debug(" close stream %d", stream_id^1); q6asm_stream_cmd(ac, CMD_CLOSE, stream_id^1); spin_lock_irqsave(&prtd->lock, flags); } if (prtd->gapless_state.stream_opened[stream_id]) { spin_unlock_irqrestore(&prtd->lock, flags); pr_debug("close stream %d", stream_id); q6asm_stream_cmd(ac, CMD_CLOSE, stream_id); spin_lock_irqsave(&prtd->lock, flags); } spin_unlock_irqrestore(&prtd->lock, flags); pdata->cstream[soc_prtd->dai_link->be_id] = NULL; if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (atomic_read(&pdata->audio_ocmem_req) > 1) atomic_dec(&pdata->audio_ocmem_req); else if (atomic_cmpxchg(&pdata->audio_ocmem_req, 1, 0)) audio_ocmem_process_req(AUDIO, false); msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); } pr_debug("%s: ocmem_req: %d\n", __func__, atomic_read(&pdata->audio_ocmem_req)); /* client buf alloc was with stream id 0, so free with the same */ ac->stream_id = 0; q6asm_audio_client_buf_free_contiguous(dir, ac); Loading Loading @@ -962,6 +981,45 @@ static int msm_compr_drain_buffer(struct msm_compr_audio *prtd, return rc; } static int msm_compr_wait_for_stream_avail(struct msm_compr_audio *prtd, unsigned long *flags) { int rc = 0; pr_debug("next session is already in opened state\n"); prtd->next_stream = 1; prtd->cmd_interrupt = 0; spin_unlock_irqrestore(&prtd->lock, *flags); /* * Wait for stream to be available, or the wait to be interrupted by * commands like flush or till a timeout of one second. */ rc = wait_event_timeout(prtd->wait_for_stream_avail, prtd->stream_available || prtd->cmd_interrupt, 1 * HZ); pr_err("%s:prtd->stream_available %d, prtd->cmd_interrupt %d rc %d\n", __func__, prtd->stream_available, prtd->cmd_interrupt, rc); spin_lock_irqsave(&prtd->lock, *flags); if (rc == 0) { pr_err("%s: wait_for_stream_avail timed out\n", __func__); rc = -ETIMEDOUT; } else if (prtd->cmd_interrupt == 1) { /* * This scenario might not happen as we do not allow * flush in transition state. */ pr_debug("%s: wait_for_stream_avail interrupted\n", __func__); prtd->cmd_interrupt = 0; prtd->stream_available = 0; rc = -EINTR; } else { prtd->stream_available = 0; rc = 0; } pr_debug("%s : rc = %d", __func__, rc); return rc; } static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) { struct snd_compr_runtime *runtime = cstream->runtime; Loading Loading @@ -1007,6 +1065,13 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) prtd->gapless_state.gapless_transition); stream_id = ac->stream_id; atomic_set(&prtd->start, 0); if (prtd->next_stream) { pr_debug("%s: interrupt next track wait queues\n", __func__); prtd->cmd_interrupt = 1; wake_up(&prtd->wait_for_stream_avail); prtd->next_stream = 0; } if (atomic_read(&prtd->eos)) { pr_debug("%s: interrupt eos wait queues", __func__); prtd->cmd_interrupt = 1; Loading Loading @@ -1273,12 +1338,43 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) spin_lock_irqsave(&prtd->lock, flags); rc = 0; stream_id = ac->stream_id^1; /*next stream in gapless*/ /* * Wait if stream 1 has not completed before honoring next * track for stream 3. Scenario happens if second clip is * small and fills in one buffer so next track will be * called immediately. */ if (prtd->gapless_state.stream_opened[stream_id]) { pr_debug("next session is already in opened state\n"); if (prtd->gapless_state.gapless_transition) { rc = msm_compr_wait_for_stream_avail(prtd, &flags); } else { /* * If session is already opened break out if * the state is not gapless transition. This * is when seek happens after the last buffer * is sent to the driver. Next track would be * called again after last buffer is sent. */ pr_debug("next session is in opened state\n"); spin_unlock_irqrestore(&prtd->lock, flags); break; } } spin_unlock_irqrestore(&prtd->lock, flags); if (rc < 0) { /* * if return type EINTR then reset to zero. Tiny * compress treats EINTR as error and prevents PARTIAL * DRAIN. EINTR is not an error. wait for stream avail * is interrupted by some other command like FLUSH. */ if (rc == -EINTR) { pr_debug("%s: EINTR reset rc to 0\n", __func__); rc = 0; } break; } rc = q6asm_stream_open_write_v2(prtd->audio_client, prtd->codec, 16, stream_id, Loading Loading @@ -1447,8 +1543,6 @@ static int msm_compr_copy(struct snd_compr_stream *cstream, * since the available bytes fits fragment_size, copy the data right away */ spin_lock_irqsave(&prtd->lock, flags); if (prtd->gapless_state.gapless_transition) prtd->gapless_state.gapless_transition = 0; prtd->bytes_received += count; if (atomic_read(&prtd->start)) { if (atomic_read(&prtd->xrun)) { Loading Loading
sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +112 −18 Original line number Diff line number Diff line Loading @@ -114,6 +114,8 @@ struct msm_compr_audio { uint32_t cmd_ack; uint32_t cmd_interrupt; uint32_t drain_ready; uint32_t stream_available; uint32_t next_stream; struct msm_compr_gapless_state gapless_state; Loading @@ -129,6 +131,7 @@ struct msm_compr_audio { wait_queue_head_t drain_wait; wait_queue_head_t flush_wait; wait_queue_head_t close_wait; wait_queue_head_t wait_for_stream_avail; spinlock_t lock; }; Loading Loading @@ -335,6 +338,8 @@ static void compr_event_handler(uint32_t opcode, prtd->gapless_state.stream_opened[stream_id] = 0; prtd->gapless_state.set_next_stream_id = false; } if (prtd->gapless_state.gapless_transition) prtd->gapless_state.gapless_transition = 0; spin_unlock(&prtd->lock); break; case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY: Loading Loading @@ -379,6 +384,17 @@ static void compr_event_handler(uint32_t opcode, break; case ASM_STREAM_CMD_CLOSE: pr_debug("ASM_DATA_CMD_CLOSE\n"); /* * wakeup wait for stream avail on stream 3 * after stream 1 ends. */ if (prtd->next_stream) { pr_debug("%s:CLOSE:wakeup wait for stream\n", __func__); prtd->stream_available = 1; wake_up(&prtd->wait_for_stream_avail); prtd->next_stream = 0; } if (atomic_read(&prtd->close) && atomic_read(&prtd->wait_on_close)) { prtd->cmd_ack = 1; Loading Loading @@ -705,6 +721,7 @@ static int msm_compr_open(struct snd_compr_stream *cstream) prtd->last_buffer = 0; prtd->first_buffer = 1; prtd->partial_drain_delay = 0; prtd->next_stream = 0; memset(&prtd->gapless_state, 0, sizeof(struct msm_compr_gapless_state)); /* * Update the use_dsp_gapless_mode from gapless struture with the value Loading @@ -728,6 +745,7 @@ static int msm_compr_open(struct snd_compr_stream *cstream) init_waitqueue_head(&prtd->drain_wait); init_waitqueue_head(&prtd->flush_wait); init_waitqueue_head(&prtd->close_wait); init_waitqueue_head(&prtd->wait_for_stream_avail); runtime->private_data = prtd; populate_codec_list(prtd); Loading Loading @@ -758,19 +776,6 @@ static int msm_compr_free(struct snd_compr_stream *cstream) unsigned long flags; pr_debug("%s\n", __func__); pdata->cstream[soc_prtd->dai_link->be_id] = NULL; if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (atomic_read(&pdata->audio_ocmem_req) > 1) atomic_dec(&pdata->audio_ocmem_req); else if (atomic_cmpxchg(&pdata->audio_ocmem_req, 1, 0)) audio_ocmem_process_req(AUDIO, false); msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); } pr_debug("%s: ocmem_req: %d\n", __func__, atomic_read(&pdata->audio_ocmem_req)); if (atomic_read(&prtd->eos)) { ret = wait_event_timeout(prtd->eos_wait, Loading @@ -791,16 +796,30 @@ static int msm_compr_free(struct snd_compr_stream *cstream) stream_id = ac->stream_id; if (prtd->gapless_state.stream_opened[stream_id^1]) { spin_unlock_irqrestore(&prtd->lock, flags); pr_debug(" close stream %d", stream_id^1); q6asm_stream_cmd(ac, CMD_CLOSE, stream_id^1); spin_lock_irqsave(&prtd->lock, flags); } if (prtd->gapless_state.stream_opened[stream_id]) { spin_unlock_irqrestore(&prtd->lock, flags); pr_debug("close stream %d", stream_id); q6asm_stream_cmd(ac, CMD_CLOSE, stream_id); spin_lock_irqsave(&prtd->lock, flags); } spin_unlock_irqrestore(&prtd->lock, flags); pdata->cstream[soc_prtd->dai_link->be_id] = NULL; if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (atomic_read(&pdata->audio_ocmem_req) > 1) atomic_dec(&pdata->audio_ocmem_req); else if (atomic_cmpxchg(&pdata->audio_ocmem_req, 1, 0)) audio_ocmem_process_req(AUDIO, false); msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); } pr_debug("%s: ocmem_req: %d\n", __func__, atomic_read(&pdata->audio_ocmem_req)); /* client buf alloc was with stream id 0, so free with the same */ ac->stream_id = 0; q6asm_audio_client_buf_free_contiguous(dir, ac); Loading Loading @@ -962,6 +981,45 @@ static int msm_compr_drain_buffer(struct msm_compr_audio *prtd, return rc; } static int msm_compr_wait_for_stream_avail(struct msm_compr_audio *prtd, unsigned long *flags) { int rc = 0; pr_debug("next session is already in opened state\n"); prtd->next_stream = 1; prtd->cmd_interrupt = 0; spin_unlock_irqrestore(&prtd->lock, *flags); /* * Wait for stream to be available, or the wait to be interrupted by * commands like flush or till a timeout of one second. */ rc = wait_event_timeout(prtd->wait_for_stream_avail, prtd->stream_available || prtd->cmd_interrupt, 1 * HZ); pr_err("%s:prtd->stream_available %d, prtd->cmd_interrupt %d rc %d\n", __func__, prtd->stream_available, prtd->cmd_interrupt, rc); spin_lock_irqsave(&prtd->lock, *flags); if (rc == 0) { pr_err("%s: wait_for_stream_avail timed out\n", __func__); rc = -ETIMEDOUT; } else if (prtd->cmd_interrupt == 1) { /* * This scenario might not happen as we do not allow * flush in transition state. */ pr_debug("%s: wait_for_stream_avail interrupted\n", __func__); prtd->cmd_interrupt = 0; prtd->stream_available = 0; rc = -EINTR; } else { prtd->stream_available = 0; rc = 0; } pr_debug("%s : rc = %d", __func__, rc); return rc; } static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) { struct snd_compr_runtime *runtime = cstream->runtime; Loading Loading @@ -1007,6 +1065,13 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) prtd->gapless_state.gapless_transition); stream_id = ac->stream_id; atomic_set(&prtd->start, 0); if (prtd->next_stream) { pr_debug("%s: interrupt next track wait queues\n", __func__); prtd->cmd_interrupt = 1; wake_up(&prtd->wait_for_stream_avail); prtd->next_stream = 0; } if (atomic_read(&prtd->eos)) { pr_debug("%s: interrupt eos wait queues", __func__); prtd->cmd_interrupt = 1; Loading Loading @@ -1273,12 +1338,43 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) spin_lock_irqsave(&prtd->lock, flags); rc = 0; stream_id = ac->stream_id^1; /*next stream in gapless*/ /* * Wait if stream 1 has not completed before honoring next * track for stream 3. Scenario happens if second clip is * small and fills in one buffer so next track will be * called immediately. */ if (prtd->gapless_state.stream_opened[stream_id]) { pr_debug("next session is already in opened state\n"); if (prtd->gapless_state.gapless_transition) { rc = msm_compr_wait_for_stream_avail(prtd, &flags); } else { /* * If session is already opened break out if * the state is not gapless transition. This * is when seek happens after the last buffer * is sent to the driver. Next track would be * called again after last buffer is sent. */ pr_debug("next session is in opened state\n"); spin_unlock_irqrestore(&prtd->lock, flags); break; } } spin_unlock_irqrestore(&prtd->lock, flags); if (rc < 0) { /* * if return type EINTR then reset to zero. Tiny * compress treats EINTR as error and prevents PARTIAL * DRAIN. EINTR is not an error. wait for stream avail * is interrupted by some other command like FLUSH. */ if (rc == -EINTR) { pr_debug("%s: EINTR reset rc to 0\n", __func__); rc = 0; } break; } rc = q6asm_stream_open_write_v2(prtd->audio_client, prtd->codec, 16, stream_id, Loading Loading @@ -1447,8 +1543,6 @@ static int msm_compr_copy(struct snd_compr_stream *cstream, * since the available bytes fits fragment_size, copy the data right away */ spin_lock_irqsave(&prtd->lock, flags); if (prtd->gapless_state.gapless_transition) prtd->gapless_state.gapless_transition = 0; prtd->bytes_received += count; if (atomic_read(&prtd->start)) { if (atomic_read(&prtd->xrun)) { Loading