staticint trace_filter_parse_entry(struct snd_sof_dev *sdev, constchar *line, struct sof_ipc_trace_filter_elem *elem, int capacity, int *counter)
{ int log_level, pipe_id, comp_id, read, ret; int len = strlen(line); int cnt = *counter;
u32 uuid_id;
/* ignore empty content */
ret = sscanf(line, " %n", &read); if (!ret && read == len) return len;
if (uuid_id > 0) {
ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_UUID,
uuid_id, elem, capacity, &cnt); if (ret) return ret;
} if (pipe_id >= 0) {
ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE,
pipe_id, elem, capacity, &cnt); if (ret) return ret;
} if (comp_id >= 0) {
ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_COMP,
comp_id, elem, capacity, &cnt); if (ret) return ret;
}
ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL |
SOF_IPC_TRACE_FILTER_ELEM_FIN,
log_level, elem, capacity, &cnt); if (ret) return ret;
/* update counter only when parsing whole entry passed */
*counter = cnt;
return len;
}
staticint trace_filter_parse(struct snd_sof_dev *sdev, char *string, int *out_elem_cnt, struct sof_ipc_trace_filter_elem **out)
{ staticconstchar entry_delimiter[] = ";"; char *entry = string; int capacity = 0; int entry_len; int cnt = 0;
/* * Each entry contains at least 1, up to TRACE_FILTER_ELEMENTS_PER_ENTRY * IPC elements, depending on content. Calculate IPC elements capacity * for the input string where each element is set.
*/ while (entry) {
capacity += TRACE_FILTER_ELEMENTS_PER_ENTRY;
entry = strchr(entry + 1, entry_delimiter[0]);
}
*out = kmalloc(capacity * sizeof(**out), GFP_KERNEL); if (!*out) return -ENOMEM;
/* split input string by ';', and parse each entry separately in trace_filter_parse_entry */ while ((entry = strsep(&string, entry_delimiter))) {
entry_len = trace_filter_parse_entry(sdev, entry, *out, capacity, &cnt); if (entry_len < 0) {
dev_err(sdev->dev, "Parsing filter entry '%s' failed with %d\n",
entry, entry_len); return -EINVAL;
}
}
*out_elem_cnt = cnt;
return 0;
}
staticint ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems, struct sof_ipc_trace_filter_elem *elems)
{ struct sof_ipc_trace_filter *msg;
size_t size; int ret;
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 host offset is less than local pos, it means write pointer of * host DMA buffer has been wrapped. We should output the trace data * at the end of host DMA buffer at first.
*/ if (host_offset < pos) return buffer_size - pos;
/* If there is available trace data now, it is unnecessary to wait. */ if (host_offset > pos) return host_offset - pos;
/* data immediately available */ if (ret) return ret;
if (priv->dtrace_draining && !trace_pos_update_expected(priv)) { /* * tracing has ended and all traces have been * read by client, return EOF
*/
priv->dtrace_draining = false; return 0;
}
/* wait for available trace data from FW */
init_waitqueue_entry(&wait, current);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&priv->trace_sleep, &wait);
if (!signal_pending(current)) { /* set timeout to max value, no error code */
schedule_timeout(MAX_SCHEDULE_TIMEOUT);
}
remove_wait_queue(&priv->trace_sleep, &wait);
/* make sure we know about any failures on the DSP side */
priv->dtrace_error = false;
/* check pos and count */ if (lpos < 0) return -EINVAL; if (!count) return 0;
/* check for buffer wrap and count overflow */
lpos_64 = lpos;
lpos = do_div(lpos_64, buffer_size);
/* get available count based on current host offset */
avail = sof_wait_dtrace_avail(sdev, lpos, buffer_size); if (priv->dtrace_error) {
dev_err(sdev->dev, "trace IO error\n"); return -EIO;
}
/* no new trace data */ if (!avail) return 0;
/* make sure count is <= avail */ if (count > avail)
count = avail;
/* * make sure that all trace data is available for the CPU as the trace * data buffer might be allocated from non consistent memory. * Note: snd_dma_buffer_sync() is called for normal audio playback and * capture streams also.
*/
snd_dma_buffer_sync(&priv->dmatb, SNDRV_DMA_SYNC_CPU); /* copy available trace data to debugfs */
rem = copy_to_user(buffer, ((u8 *)(dfse->buf) + lpos), count); if (rem) return -EFAULT;
*ppos += count;
/* move debugfs reading position */ return count;
}
/* send IPC to the DSP */
priv->dtrace_state = SOF_DTRACE_INITIALIZING;
ret = sof_ipc_tx_message_no_reply(sdev->ipc, ¶ms, sizeof(params)); if (ret < 0) {
dev_err(sdev->dev, "can't set params for DMA for trace %d\n", ret); goto trace_release;
}
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;
}
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, "DSP trace buffer overflow %u bytes. Total messages %d\n",
posn->overflow, posn->messages);
return 0;
}
/* an error has occurred within the DSP that prevents further trace */ staticvoid ipc3_dtrace_fw_crashed(struct snd_sof_dev *sdev)
{ struct sof_dtrace_priv *priv = sdev->fw_trace_data;
if (!sdev->fw_trace_is_supported || priv->dtrace_state == SOF_DTRACE_DISABLED) return;
ret = sof_dtrace_host_trigger(sdev, SNDRV_PCM_TRIGGER_STOP); if (ret < 0)
dev_err(sdev->dev, "Host dtrace trigger stop failed: %d\n", ret);
priv->dtrace_state = SOF_DTRACE_STOPPED;
/* * stop and free trace DMA in the DSP. TRACE_DMA_FREE is only supported from * ABI 3.20.0 onwards
*/ if (v->abi_version >= SOF_ABI_VER(3, 20, 0)) {
hdr.size = sizeof(hdr);
hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_FREE;
ret = sof_ipc_tx_message_no_reply(sdev->ipc, &hdr, hdr.size); if (ret < 0)
dev_err(sdev->dev, "DMA_TRACE_FREE failed with error: %d\n", ret);
}
if (only_stop) goto out;
ret = sof_dtrace_host_release(sdev); if (ret < 0)
dev_err(sdev->dev, "Host dtrace release failed %d\n", ret);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.