in coresight/coresight-etm-perf.c [502:596]
static void etm_event_stop(struct perf_event *event, int mode)
{
int cpu = smp_processor_id();
unsigned long size;
struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
struct etm_ctxt *ctxt = this_cpu_ptr(&etm_ctxt);
struct perf_output_handle *handle = &ctxt->handle;
struct etm_event_data *event_data;
struct list_head *path;
/*
* If we still have access to the event_data via handle,
* confirm that we haven't messed up the tracking.
*/
if (handle->event &&
WARN_ON(perf_get_aux(handle) != ctxt->event_data))
return;
event_data = ctxt->event_data;
/* Clear the event_data as this ETM is stopping the trace. */
ctxt->event_data = NULL;
if (event->hw.state == PERF_HES_STOPPED)
return;
/* We must have a valid event_data for a running event */
if (WARN_ON(!event_data))
return;
/*
* Check if this ETM was allowed to trace, as decided at
* etm_setup_aux(). If it wasn't allowed to trace, then
* nothing needs to be torn down other than outputting a
* zero sized record.
*/
if (handle->event && (mode & PERF_EF_UPDATE) &&
!cpumask_test_cpu(cpu, &event_data->mask)) {
event->hw.state = PERF_HES_STOPPED;
perf_aux_output_end(handle, 0);
return;
}
if (!csdev)
return;
path = etm_event_cpu_path(event_data, cpu);
if (!path)
return;
sink = coresight_get_sink(path);
if (!sink)
return;
/* stop tracer */
source_ops(csdev)->disable(csdev, event);
/* tell the core */
event->hw.state = PERF_HES_STOPPED;
/*
* If the handle is not bound to an event anymore
* (e.g, the sink driver was unable to restart the
* handle due to lack of buffer space), we don't
* have to do anything here.
*/
if (handle->event && (mode & PERF_EF_UPDATE)) {
if (WARN_ON_ONCE(handle->event != event))
return;
/* update trace information */
if (!sink_ops(sink)->update_buffer)
return;
size = sink_ops(sink)->update_buffer(sink, handle,
event_data->snk_config);
/*
* Make sure the handle is still valid as the
* sink could have closed it from an IRQ.
* The sink driver must handle the race with
* update_buffer() and IRQ. Thus either we
* should get a valid handle and valid size
* (which may be 0).
*
* But we should never get a non-zero size with
* an invalid handle.
*/
if (READ_ONCE(handle->event))
perf_aux_output_end(handle, size);
else
WARN_ON(size);
}
/* Disabling the path make its elements available to other sessions */
coresight_disable_path(path);
}