diff mbox series

[v5,2/5] ASoC: q6apm: add q6apm_get_hw_pointer helper

Message ID 20250314174800.10142-3-srinivas.kandagatla@linaro.org
State Superseded
Headers show
Series ASoC: q6apm: fix under runs and fragment sizes | expand

Commit Message

Srinivas Kandagatla March 14, 2025, 5:47 p.m. UTC
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

Implement an helper function in q6apm to be able to read the current
hardware pointer for both read and write buffers.

This should help q6apm-dai to get the hardware pointer consistently
without it doing manual calculation, which could go wrong in some race
conditions.

Fixes: 9b4fe0f1cd79 ("ASoC: qdsp6: audioreach: add q6apm-dai support")
Cc: stable@vger.kernel.org
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Tested-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Tested-by: Johan Hovold <johan+linaro@kernel.org>
---
 sound/soc/qcom/qdsp6/q6apm.c | 18 +++++++++++++++++-
 sound/soc/qcom/qdsp6/q6apm.h |  3 +++
 2 files changed, 20 insertions(+), 1 deletion(-)

Comments

Johan Hovold April 7, 2025, 11:25 a.m. UTC | #1
Hi Srini,

On Fri, Mar 14, 2025 at 05:47:57PM +0000, Srinivas Kandagatla wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> 
> Implement an helper function in q6apm to be able to read the current
> hardware pointer for both read and write buffers.
> 
> This should help q6apm-dai to get the hardware pointer consistently
> without it doing manual calculation, which could go wrong in some race
> conditions.
 
> +int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
> +{
> +	struct audioreach_graph_data *data;
> +
> +	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
> +		data = &graph->rx_data;
> +	else
> +		data = &graph->tx_data;
> +
> +	return (int)atomic_read(&data->hw_ptr);
> +}
> +EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);

> @@ -553,6 +567,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
>  		rd_done = data->payload;
>  		phys = graph->tx_data.buf[hdr->token].phys;
>  		mutex_unlock(&graph->lock);
> +		/* token numbering starts at 0 */
> +		atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
>  
>  		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
>  		    lower_32_bits(phys) == rd_done->buf_addr_lsw) {

			graph->result.opcode = hdr->opcode;
                        graph->result.status = rd_done->status;
                        if (graph->cb)
                                graph->cb(client_event, hdr->token, data->payload, graph->priv);
                } else {
                        dev_err(dev, "RD BUFF Unexpected addr %08x-%08x\n", rd_done->buf_addr_lsw,
                                rd_done->buf_addr_msw);
                }

I just hit the following error on the T14s with 6.15-rc1 that I've never
seen before and which looks like it could be related to this series:

	q6apm-dai 6800000.remoteproc:glink-edge:gpr:service@1:dais: RD BUFF Unexpected addr ffe0d200-00000001

Any ideas about what may be causing this?

Johan
Srinivas Kandagatla April 8, 2025, 8:07 a.m. UTC | #2
Thanks Johan,

On 07/04/2025 12:25, Johan Hovold wrote:
> Hi Srini,
> 
> On Fri, Mar 14, 2025 at 05:47:57PM +0000, Srinivas Kandagatla wrote:
>> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>
>> Implement an helper function in q6apm to be able to read the current
>> hardware pointer for both read and write buffers.
>>
>> This should help q6apm-dai to get the hardware pointer consistently
>> without it doing manual calculation, which could go wrong in some race
>> conditions.
>   
>> +int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
>> +{
>> +	struct audioreach_graph_data *data;
>> +
>> +	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
>> +		data = &graph->rx_data;
>> +	else
>> +		data = &graph->tx_data;
>> +
>> +	return (int)atomic_read(&data->hw_ptr);
>> +}
>> +EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);
> 
>> @@ -553,6 +567,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
>>   		rd_done = data->payload;
>>   		phys = graph->tx_data.buf[hdr->token].phys;
>>   		mutex_unlock(&graph->lock);
>> +		/* token numbering starts at 0 */
>> +		atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
>>   
>>   		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
>>   		    lower_32_bits(phys) == rd_done->buf_addr_lsw) {
> 
> 			graph->result.opcode = hdr->opcode;
>                          graph->result.status = rd_done->status;
>                          if (graph->cb)
>                                  graph->cb(client_event, hdr->token, data->payload, graph->priv);
>                  } else {
>                          dev_err(dev, "RD BUFF Unexpected addr %08x-%08x\n", rd_done->buf_addr_lsw,
>                                  rd_done->buf_addr_msw);
>                  }
> 
> I just hit the following error on the T14s with 6.15-rc1 that I've never
> seen before and which looks like it could be related to this series:
Its unlikely, but the timings have changed here.
I have not seen it either, but I will try to reproduce this with 6.15-rc1.
> 
> 	q6apm-dai 6800000.remoteproc:glink-edge:gpr:service@1:dais: RD BUFF Unexpected addr ffe0d200-00000001
> 
> Any ideas about what may be causing this?
How easy is this to reproduce?

--srini
> 
> Johan
Johan Hovold April 10, 2025, 7:16 a.m. UTC | #3
On Tue, Apr 08, 2025 at 09:07:27AM +0100, Srinivas Kandagatla wrote:
> On 07/04/2025 12:25, Johan Hovold wrote:
> > On Fri, Mar 14, 2025 at 05:47:57PM +0000, Srinivas Kandagatla wrote:
> >> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> >>
> >> Implement an helper function in q6apm to be able to read the current
> >> hardware pointer for both read and write buffers.
> >>
> >> This should help q6apm-dai to get the hardware pointer consistently
> >> without it doing manual calculation, which could go wrong in some race
> >> conditions.

> >> @@ -553,6 +567,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
> >>   		rd_done = data->payload;
> >>   		phys = graph->tx_data.buf[hdr->token].phys;
> >>   		mutex_unlock(&graph->lock);
> >> +		/* token numbering starts at 0 */
> >> +		atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
> >>   
> >>   		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
> >>   		    lower_32_bits(phys) == rd_done->buf_addr_lsw) {
> > 
> > 			graph->result.opcode = hdr->opcode;
> >                          graph->result.status = rd_done->status;
> >                          if (graph->cb)
> >                                  graph->cb(client_event, hdr->token, data->payload, graph->priv);
> >                  } else {
> >                          dev_err(dev, "RD BUFF Unexpected addr %08x-%08x\n", rd_done->buf_addr_lsw,
> >                                  rd_done->buf_addr_msw);
> >                  }
> > 
> > I just hit the following error on the T14s with 6.15-rc1 that I've never
> > seen before and which looks like it could be related to this series:

> Its unlikely, but the timings have changed here.
> I have not seen it either, but I will try to reproduce this with 6.15-rc1.
> > 
> > 	q6apm-dai 6800000.remoteproc:glink-edge:gpr:service@1:dais: RD BUFF Unexpected addr ffe0d200-00000001
> > 
> > Any ideas about what may be causing this?

> How easy is this to reproduce?

I've only noticed this error once on the first boot of 6.15-rc1, and it
does not seem to show up again now.

I did a fair bit of testing with this series on 6.14-rcs, but did not
check the logs while doing so (and there's nothing in the logs I still
have).

Johan
diff mbox series

Patch

diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 2a2a5bd98110..ca57413cb784 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -494,6 +494,19 @@  int q6apm_read(struct q6apm_graph *graph)
 }
 EXPORT_SYMBOL_GPL(q6apm_read);
 
+int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
+{
+	struct audioreach_graph_data *data;
+
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+		data = &graph->rx_data;
+	else
+		data = &graph->tx_data;
+
+	return (int)atomic_read(&data->hw_ptr);
+}
+EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);
+
 static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
 {
 	struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
@@ -520,7 +533,8 @@  static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
 		done = data->payload;
 		phys = graph->rx_data.buf[token].phys;
 		mutex_unlock(&graph->lock);
-
+		/* token numbering starts at 0 */
+		atomic_set(&graph->rx_data.hw_ptr, token + 1);
 		if (lower_32_bits(phys) == done->buf_addr_lsw &&
 		    upper_32_bits(phys) == done->buf_addr_msw) {
 			graph->result.opcode = hdr->opcode;
@@ -553,6 +567,8 @@  static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
 		rd_done = data->payload;
 		phys = graph->tx_data.buf[hdr->token].phys;
 		mutex_unlock(&graph->lock);
+		/* token numbering starts at 0 */
+		atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
 
 		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
 		    lower_32_bits(phys) == rd_done->buf_addr_lsw) {
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index c248c8d2b1ab..7ce08b401e31 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -2,6 +2,7 @@ 
 #ifndef __Q6APM_H__
 #define __Q6APM_H__
 #include <linux/types.h>
+#include <linux/atomic.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/kernel.h>
@@ -77,6 +78,7 @@  struct audioreach_graph_data {
 	uint32_t num_periods;
 	uint32_t dsp_buf;
 	uint32_t mem_map_handle;
+	atomic_t hw_ptr;
 };
 
 struct audioreach_graph {
@@ -150,4 +152,5 @@  int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph,
 int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
 int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
 int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id);
+int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir);
 #endif /* __APM_GRAPH_ */