static int l2_cache_event_init()

in qcom_l2_pmu.c [438:539]


static int l2_cache_event_init(struct perf_event *event)
{
	struct hw_perf_event *hwc = &event->hw;
	struct cluster_pmu *cluster;
	struct perf_event *sibling;
	struct l2cache_pmu *l2cache_pmu;

	if (event->attr.type != event->pmu->type)
		return -ENOENT;

	l2cache_pmu = to_l2cache_pmu(event->pmu);

	if (hwc->sample_period) {
		dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
				    "Sampling not supported\n");
		return -EOPNOTSUPP;
	}

	if (event->cpu < 0) {
		dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
				    "Per-task mode not supported\n");
		return -EOPNOTSUPP;
	}

	if (((L2_EVT_GROUP(event->attr.config) > L2_EVT_GROUP_MAX) ||
	     ((event->attr.config & ~L2_EVT_MASK) != 0)) &&
	    (event->attr.config != L2CYCLE_CTR_RAW_CODE)) {
		dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
				    "Invalid config %llx\n",
				    event->attr.config);
		return -EINVAL;
	}

	/* Don't allow groups with mixed PMUs, except for s/w events */
	if (event->group_leader->pmu != event->pmu &&
	    !is_software_event(event->group_leader)) {
		dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
			 "Can't create mixed PMU group\n");
		return -EINVAL;
	}

	for_each_sibling_event(sibling, event->group_leader) {
		if (sibling->pmu != event->pmu &&
		    !is_software_event(sibling)) {
			dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
				 "Can't create mixed PMU group\n");
			return -EINVAL;
		}
	}

	cluster = get_cluster_pmu(l2cache_pmu, event->cpu);
	if (!cluster) {
		/* CPU has not been initialised */
		dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
			"CPU%d not associated with L2 cluster\n", event->cpu);
		return -EINVAL;
	}

	/* Ensure all events in a group are on the same cpu */
	if ((event->group_leader != event) &&
	    (cluster->on_cpu != event->group_leader->cpu)) {
		dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
			 "Can't create group on CPUs %d and %d",
			 event->cpu, event->group_leader->cpu);
		return -EINVAL;
	}

	if ((event != event->group_leader) &&
	    !is_software_event(event->group_leader) &&
	    (L2_EVT_GROUP(event->group_leader->attr.config) ==
	     L2_EVT_GROUP(event->attr.config))) {
		dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
			 "Column exclusion: conflicting events %llx %llx\n",
		       event->group_leader->attr.config,
		       event->attr.config);
		return -EINVAL;
	}

	for_each_sibling_event(sibling, event->group_leader) {
		if ((sibling != event) &&
		    !is_software_event(sibling) &&
		    (L2_EVT_GROUP(sibling->attr.config) ==
		     L2_EVT_GROUP(event->attr.config))) {
			dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
			     "Column exclusion: conflicting events %llx %llx\n",
					    sibling->attr.config,
					    event->attr.config);
			return -EINVAL;
		}
	}

	hwc->idx = -1;
	hwc->config_base = event->attr.config;

	/*
	 * Ensure all events are on the same cpu so all events are in the
	 * same cpu context, to avoid races on pmu_enable etc.
	 */
	event->cpu = cluster->on_cpu;

	return 0;
}