Merge tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[sfrench/cifs-2.6.git] / sound / soc / sof / ipc3-dtrace.c
index b4e1343f9138f0251eaf73866400deabb8487924..b815b0244d9e43b82d32cf238a0e194c557c447d 100644 (file)
@@ -18,6 +18,7 @@
 enum sof_dtrace_state {
        SOF_DTRACE_DISABLED,
        SOF_DTRACE_STOPPED,
+       SOF_DTRACE_INITIALIZING,
        SOF_DTRACE_ENABLED,
 };
 
@@ -32,6 +33,15 @@ struct sof_dtrace_priv {
        enum sof_dtrace_state dtrace_state;
 };
 
+static bool trace_pos_update_expected(struct sof_dtrace_priv *priv)
+{
+       if (priv->dtrace_state == SOF_DTRACE_ENABLED ||
+           priv->dtrace_state == SOF_DTRACE_INITIALIZING)
+               return true;
+
+       return false;
+}
+
 static int trace_filter_append_elem(struct snd_sof_dev *sdev, u32 key, u32 value,
                                    struct sof_ipc_trace_filter_elem *elem_list,
                                    int capacity, int *counter)
@@ -157,9 +167,8 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
        msg->elem_cnt = num_elems;
        memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems));
 
-       ret = pm_runtime_get_sync(sdev->dev);
+       ret = pm_runtime_resume_and_get(sdev->dev);
        if (ret < 0 && ret != -EACCES) {
-               pm_runtime_put_noidle(sdev->dev);
                dev_err(sdev->dev, "enabling device failed: %d\n", ret);
                goto error;
        }
@@ -242,6 +251,21 @@ static int debugfs_create_trace_filter(struct snd_sof_dev *sdev)
        return 0;
 }
 
+static bool sof_dtrace_set_host_offset(struct sof_dtrace_priv *priv, u32 new_offset)
+{
+       u32 host_offset = READ_ONCE(priv->host_offset);
+
+       if (host_offset != new_offset) {
+               /* This is a bit paranoid and unlikely that it is needed */
+               u32 ret = cmpxchg(&priv->host_offset, host_offset, new_offset);
+
+               if (ret == host_offset)
+                       return true;
+       }
+
+       return false;
+}
+
 static size_t sof_dtrace_avail(struct snd_sof_dev *sdev,
                               loff_t pos, size_t buffer_size)
 {
@@ -274,7 +298,7 @@ static size_t sof_wait_dtrace_avail(struct snd_sof_dev *sdev, loff_t pos,
        if (ret)
                return ret;
 
-       if (priv->dtrace_state != SOF_DTRACE_ENABLED && priv->dtrace_draining) {
+       if (priv->dtrace_draining && !trace_pos_update_expected(priv)) {
                /*
                 * tracing has ended and all traces have been
                 * read by client, return EOF
@@ -328,6 +352,10 @@ static ssize_t dfsentry_dtrace_read(struct file *file, char __user *buffer,
                return -EIO;
        }
 
+       /* no new trace data */
+       if (!avail)
+               return 0;
+
        /* make sure count is <= avail */
        if (count > avail)
                count = avail;
@@ -358,7 +386,7 @@ static int dfsentry_dtrace_release(struct inode *inode, struct file *file)
 
        /* avoid duplicate traces at next open */
        if (priv->dtrace_state != SOF_DTRACE_ENABLED)
-               priv->host_offset = 0;
+               sof_dtrace_set_host_offset(priv, 0);
 
        return 0;
 }
@@ -434,7 +462,7 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
        params.buffer.pages = priv->dma_trace_pages;
        params.stream_tag = 0;
 
-       priv->host_offset = 0;
+       sof_dtrace_set_host_offset(priv, 0);
        priv->dtrace_draining = false;
 
        ret = sof_dtrace_host_init(sdev, &priv->dmatb, &params);
@@ -442,9 +470,10 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
                dev_err(sdev->dev, "Host dtrace init failed: %d\n", ret);
                return ret;
        }
-       dev_dbg(sdev->dev, "%s: stream_tag: %d\n", __func__, params.stream_tag);
+       dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag);
 
        /* send IPC to the DSP */
+       priv->dtrace_state = SOF_DTRACE_INITIALIZING;
        ret = sof_ipc_tx_message(sdev->ipc, &params, sizeof(params), &ipc_reply, sizeof(ipc_reply));
        if (ret < 0) {
                dev_err(sdev->dev, "can't set params for DMA for trace %d\n", ret);
@@ -452,17 +481,18 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
        }
 
 start:
+       priv->dtrace_state = SOF_DTRACE_ENABLED;
+
        ret = sof_dtrace_host_trigger(sdev, SNDRV_PCM_TRIGGER_START);
        if (ret < 0) {
                dev_err(sdev->dev, "Host dtrace trigger start failed: %d\n", ret);
                goto trace_release;
        }
 
-       priv->dtrace_state = SOF_DTRACE_ENABLED;
-
        return 0;
 
 trace_release:
+       priv->dtrace_state = SOF_DTRACE_DISABLED;
        sof_dtrace_host_release(sdev);
        return ret;
 }
@@ -514,8 +544,7 @@ static int ipc3_dtrace_init(struct snd_sof_dev *sdev)
                goto table_err;
 
        priv->dma_trace_pages = ret;
-       dev_dbg(sdev->dev, "%s: dma_trace_pages: %d\n", __func__,
-               priv->dma_trace_pages);
+       dev_dbg(sdev->dev, "dma_trace_pages: %d\n", priv->dma_trace_pages);
 
        if (sdev->first_boot) {
                ret = debugfs_create_dtrace(sdev);
@@ -546,11 +575,9 @@ int ipc3_dtrace_posn_update(struct snd_sof_dev *sdev,
        if (!sdev->fw_trace_is_supported)
                return 0;
 
-       if (priv->dtrace_state == SOF_DTRACE_ENABLED &&
-           priv->host_offset != posn->host_offset) {
-               priv->host_offset = posn->host_offset;
+       if (trace_pos_update_expected(priv) &&
+           sof_dtrace_set_host_offset(priv, posn->host_offset))
                wake_up(&priv->trace_sleep);
-       }
 
        if (posn->overflow != 0)
                dev_err(sdev->dev,