in kernel/perf_event.c [100:156]
static int __hw_perf_event_init(struct perf_event *event)
{
struct perf_event_attr *attr = &event->attr;
struct hw_perf_event *hwc = &event->hw;
int config = -1;
int err;
if (!sh_pmu_initialized())
return -ENODEV;
/*
* See if we need to reserve the counter.
*
* If no events are currently in use, then we have to take a
* mutex to ensure that we don't race with another task doing
* reserve_pmc_hardware or release_pmc_hardware.
*/
err = 0;
if (!atomic_inc_not_zero(&num_events)) {
mutex_lock(&pmc_reserve_mutex);
if (atomic_read(&num_events) == 0 &&
reserve_pmc_hardware())
err = -EBUSY;
else
atomic_inc(&num_events);
mutex_unlock(&pmc_reserve_mutex);
}
if (err)
return err;
event->destroy = hw_perf_event_destroy;
switch (attr->type) {
case PERF_TYPE_RAW:
config = attr->config & sh_pmu->raw_event_mask;
break;
case PERF_TYPE_HW_CACHE:
err = hw_perf_cache_event(attr->config, &config);
if (err)
return err;
break;
case PERF_TYPE_HARDWARE:
if (attr->config >= sh_pmu->max_events)
return -EINVAL;
config = sh_pmu->event_map(attr->config);
break;
}
if (config == -1)
return -EINVAL;
hwc->config |= config;
return 0;
}