static int arm_cmn_event_init()

in arm-cmn.c [1198:1260]


static int arm_cmn_event_init(struct perf_event *event)
{
	struct arm_cmn *cmn = to_cmn(event->pmu);
	struct arm_cmn_hw_event *hw = to_cmn_hw(event);
	struct arm_cmn_node *dn;
	enum cmn_node_type type;
	bool bynodeid;
	u16 nodeid, eventid;

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

	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
		return -EINVAL;

	event->cpu = cmn->cpu;
	if (event->cpu < 0)
		return -EINVAL;

	type = CMN_EVENT_TYPE(event);
	/* DTC events (i.e. cycles) already have everything they need */
	if (type == CMN_TYPE_DTC)
		return 0;

	/* For watchpoints we need the actual XP node here */
	if (type == CMN_TYPE_WP) {
		type = CMN_TYPE_XP;
		/* ...and we need a "real" direction */
		eventid = CMN_EVENT_EVENTID(event);
		if (eventid != CMN_WP_UP && eventid != CMN_WP_DOWN)
			return -EINVAL;
		/* ...but the DTM may depend on which port we're watching */
		if (cmn->multi_dtm)
			hw->dtm_offset = CMN_EVENT_WP_DEV_SEL(event) / 2;
	}

	bynodeid = CMN_EVENT_BYNODEID(event);
	nodeid = CMN_EVENT_NODEID(event);

	hw->dn = arm_cmn_node(cmn, type);
	if (!hw->dn)
		return -EINVAL;
	for (dn = hw->dn; dn->type == type; dn++) {
		if (bynodeid && dn->id != nodeid) {
			hw->dn++;
			continue;
		}
		hw->dtcs_used |= arm_cmn_node_to_xp(cmn, dn)->dtc;
		hw->num_dns++;
		if (bynodeid)
			break;
	}

	if (!hw->num_dns) {
		struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, nodeid);

		dev_dbg(cmn->dev, "invalid node 0x%x (%d,%d,%d,%d) type 0x%x\n",
			nodeid, nid.x, nid.y, nid.port, nid.dev, type);
		return -EINVAL;
	}

	return arm_cmn_validate_group(cmn, event);
}