Commit ba70ffa7 authored by Will Deacon's avatar Will Deacon
Browse files

Merge branch 'for-next/perf' of...

Merge branch 'for-next/perf' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux

 into aarch64/for-next/core

Pull in arm perf updates, including support for 64-bit (chained) event
counters and some non-critical fixes for some of the system PMU drivers.

Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parents c5157101 809092dc
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -233,7 +233,7 @@ armv6_pmcr_counter_has_overflowed(unsigned long pmcr,
	return ret;
}

static inline u32 armv6pmu_read_counter(struct perf_event *event)
static inline u64 armv6pmu_read_counter(struct perf_event *event)
{
	struct hw_perf_event *hwc = &event->hw;
	int counter = hwc->idx;
@@ -251,7 +251,7 @@ static inline u32 armv6pmu_read_counter(struct perf_event *event)
	return value;
}

static inline void armv6pmu_write_counter(struct perf_event *event, u32 value)
static inline void armv6pmu_write_counter(struct perf_event *event, u64 value)
{
	struct hw_perf_event *hwc = &event->hw;
	int counter = hwc->idx;
@@ -411,6 +411,12 @@ armv6pmu_get_event_idx(struct pmu_hw_events *cpuc,
	}
}

static void armv6pmu_clear_event_idx(struct pmu_hw_events *cpuc,
				     struct perf_event *event)
{
	clear_bit(event->hw.idx, cpuc->used_mask);
}

static void armv6pmu_disable_event(struct perf_event *event)
{
	unsigned long val, mask, evt, flags;
@@ -491,11 +497,11 @@ static void armv6pmu_init(struct arm_pmu *cpu_pmu)
	cpu_pmu->read_counter	= armv6pmu_read_counter;
	cpu_pmu->write_counter	= armv6pmu_write_counter;
	cpu_pmu->get_event_idx	= armv6pmu_get_event_idx;
	cpu_pmu->clear_event_idx = armv6pmu_clear_event_idx;
	cpu_pmu->start		= armv6pmu_start;
	cpu_pmu->stop		= armv6pmu_stop;
	cpu_pmu->map_event	= armv6_map_event;
	cpu_pmu->num_events	= 3;
	cpu_pmu->max_period	= (1LLU << 32) - 1;
}

static int armv6_1136_pmu_init(struct arm_pmu *cpu_pmu)
@@ -542,11 +548,11 @@ static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
	cpu_pmu->read_counter	= armv6pmu_read_counter;
	cpu_pmu->write_counter	= armv6pmu_write_counter;
	cpu_pmu->get_event_idx	= armv6pmu_get_event_idx;
	cpu_pmu->clear_event_idx = armv6pmu_clear_event_idx;
	cpu_pmu->start		= armv6pmu_start;
	cpu_pmu->stop		= armv6pmu_stop;
	cpu_pmu->map_event	= armv6mpcore_map_event;
	cpu_pmu->num_events	= 3;
	cpu_pmu->max_period	= (1LLU << 32) - 1;

	return 0;
}
+12 −3
Original line number Diff line number Diff line
@@ -743,7 +743,7 @@ static inline void armv7_pmnc_select_counter(int idx)
	isb();
}

static inline u32 armv7pmu_read_counter(struct perf_event *event)
static inline u64 armv7pmu_read_counter(struct perf_event *event)
{
	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;
@@ -763,7 +763,7 @@ static inline u32 armv7pmu_read_counter(struct perf_event *event)
	return value;
}

static inline void armv7pmu_write_counter(struct perf_event *event, u32 value)
static inline void armv7pmu_write_counter(struct perf_event *event, u64 value)
{
	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;
@@ -1058,6 +1058,12 @@ static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc,
	return -EAGAIN;
}

static void armv7pmu_clear_event_idx(struct pmu_hw_events *cpuc,
				     struct perf_event *event)
{
	clear_bit(event->hw.idx, cpuc->used_mask);
}

/*
 * Add an event filter to a given event. This will only work for PMUv2 PMUs.
 */
@@ -1167,10 +1173,10 @@ static void armv7pmu_init(struct arm_pmu *cpu_pmu)
	cpu_pmu->read_counter	= armv7pmu_read_counter;
	cpu_pmu->write_counter	= armv7pmu_write_counter;
	cpu_pmu->get_event_idx	= armv7pmu_get_event_idx;
	cpu_pmu->clear_event_idx = armv7pmu_clear_event_idx;
	cpu_pmu->start		= armv7pmu_start;
	cpu_pmu->stop		= armv7pmu_stop;
	cpu_pmu->reset		= armv7pmu_reset;
	cpu_pmu->max_period	= (1LLU << 32) - 1;
};

static void armv7_read_num_pmnc_events(void *info)
@@ -1638,6 +1644,7 @@ static void krait_pmu_clear_event_idx(struct pmu_hw_events *cpuc,
	bool venum_event = EVENT_VENUM(hwc->config_base);
	bool krait_event = EVENT_CPU(hwc->config_base);

	armv7pmu_clear_event_idx(cpuc, event);
	if (venum_event || krait_event) {
		bit = krait_event_to_bit(event, region, group);
		clear_bit(bit, cpuc->used_mask);
@@ -1967,6 +1974,7 @@ static void scorpion_pmu_clear_event_idx(struct pmu_hw_events *cpuc,
	bool venum_event = EVENT_VENUM(hwc->config_base);
	bool scorpion_event = EVENT_CPU(hwc->config_base);

	armv7pmu_clear_event_idx(cpuc, event);
	if (venum_event || scorpion_event) {
		bit = scorpion_event_to_bit(event, region, group);
		clear_bit(bit, cpuc->used_mask);
@@ -2030,6 +2038,7 @@ static struct platform_driver armv7_pmu_driver = {
	.driver		= {
		.name	= "armv7-pmu",
		.of_match_table = armv7_pmu_of_device_ids,
		.suppress_bind_attrs = true,
	},
	.probe		= armv7_pmu_device_probe,
};
+12 −6
Original line number Diff line number Diff line
@@ -292,6 +292,12 @@ xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc,
	}
}

static void xscalepmu_clear_event_idx(struct pmu_hw_events *cpuc,
				     struct perf_event *event)
{
	clear_bit(event->hw.idx, cpuc->used_mask);
}

static void xscale1pmu_start(struct arm_pmu *cpu_pmu)
{
	unsigned long flags, val;
@@ -316,7 +322,7 @@ static void xscale1pmu_stop(struct arm_pmu *cpu_pmu)
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}

static inline u32 xscale1pmu_read_counter(struct perf_event *event)
static inline u64 xscale1pmu_read_counter(struct perf_event *event)
{
	struct hw_perf_event *hwc = &event->hw;
	int counter = hwc->idx;
@@ -337,7 +343,7 @@ static inline u32 xscale1pmu_read_counter(struct perf_event *event)
	return val;
}

static inline void xscale1pmu_write_counter(struct perf_event *event, u32 val)
static inline void xscale1pmu_write_counter(struct perf_event *event, u64 val)
{
	struct hw_perf_event *hwc = &event->hw;
	int counter = hwc->idx;
@@ -370,11 +376,11 @@ static int xscale1pmu_init(struct arm_pmu *cpu_pmu)
	cpu_pmu->read_counter	= xscale1pmu_read_counter;
	cpu_pmu->write_counter	= xscale1pmu_write_counter;
	cpu_pmu->get_event_idx	= xscale1pmu_get_event_idx;
	cpu_pmu->clear_event_idx = xscalepmu_clear_event_idx;
	cpu_pmu->start		= xscale1pmu_start;
	cpu_pmu->stop		= xscale1pmu_stop;
	cpu_pmu->map_event	= xscale_map_event;
	cpu_pmu->num_events	= 3;
	cpu_pmu->max_period	= (1LLU << 32) - 1;

	return 0;
}
@@ -679,7 +685,7 @@ static void xscale2pmu_stop(struct arm_pmu *cpu_pmu)
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}

static inline u32 xscale2pmu_read_counter(struct perf_event *event)
static inline u64 xscale2pmu_read_counter(struct perf_event *event)
{
	struct hw_perf_event *hwc = &event->hw;
	int counter = hwc->idx;
@@ -706,7 +712,7 @@ static inline u32 xscale2pmu_read_counter(struct perf_event *event)
	return val;
}

static inline void xscale2pmu_write_counter(struct perf_event *event, u32 val)
static inline void xscale2pmu_write_counter(struct perf_event *event, u64 val)
{
	struct hw_perf_event *hwc = &event->hw;
	int counter = hwc->idx;
@@ -739,11 +745,11 @@ static int xscale2pmu_init(struct arm_pmu *cpu_pmu)
	cpu_pmu->read_counter	= xscale2pmu_read_counter;
	cpu_pmu->write_counter	= xscale2pmu_write_counter;
	cpu_pmu->get_event_idx	= xscale2pmu_get_event_idx;
	cpu_pmu->clear_event_idx = xscalepmu_clear_event_idx;
	cpu_pmu->start		= xscale2pmu_start;
	cpu_pmu->stop		= xscale2pmu_stop;
	cpu_pmu->map_event	= xscale_map_event;
	cpu_pmu->num_events	= 5;
	cpu_pmu->max_period	= (1LLU << 32) - 1;

	return 0;
}
+201 −50
Original line number Diff line number Diff line
@@ -446,9 +446,16 @@ static struct attribute_group armv8_pmuv3_events_attr_group = {
};

PMU_FORMAT_ATTR(event, "config:0-15");
PMU_FORMAT_ATTR(long, "config1:0");

static inline bool armv8pmu_event_is_64bit(struct perf_event *event)
{
	return event->attr.config1 & 0x1;
}

static struct attribute *armv8_pmuv3_format_attrs[] = {
	&format_attr_event.attr,
	&format_attr_long.attr,
	NULL,
};

@@ -465,6 +472,21 @@ static struct attribute_group armv8_pmuv3_format_attr_group = {
#define	ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
	(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)

/*
 * We must chain two programmable counters for 64 bit events,
 * except when we have allocated the 64bit cycle counter (for CPU
 * cycles event). This must be called only when the event has
 * a counter allocated.
 */
static inline bool armv8pmu_event_is_chained(struct perf_event *event)
{
	int idx = event->hw.idx;

	return !WARN_ON(idx < 0) &&
	       armv8pmu_event_is_64bit(event) &&
	       (idx != ARMV8_IDX_CYCLE_COUNTER);
}

/*
 * ARMv8 low level PMU access
 */
@@ -503,34 +525,68 @@ static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx)
	return pmnc & BIT(ARMV8_IDX_TO_COUNTER(idx));
}

static inline int armv8pmu_select_counter(int idx)
static inline void armv8pmu_select_counter(int idx)
{
	u32 counter = ARMV8_IDX_TO_COUNTER(idx);
	write_sysreg(counter, pmselr_el0);
	isb();
}

	return idx;
static inline u32 armv8pmu_read_evcntr(int idx)
{
	armv8pmu_select_counter(idx);
	return read_sysreg(pmxevcntr_el0);
}

static inline u64 armv8pmu_read_hw_counter(struct perf_event *event)
{
	int idx = event->hw.idx;
	u64 val = 0;

	val = armv8pmu_read_evcntr(idx);
	if (armv8pmu_event_is_chained(event))
		val = (val << 32) | armv8pmu_read_evcntr(idx - 1);
	return val;
}

static inline u32 armv8pmu_read_counter(struct perf_event *event)
static inline u64 armv8pmu_read_counter(struct perf_event *event)
{
	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;
	int idx = hwc->idx;
	u32 value = 0;
	u64 value = 0;

	if (!armv8pmu_counter_valid(cpu_pmu, idx))
		pr_err("CPU%u reading wrong counter %d\n",
			smp_processor_id(), idx);
	else if (idx == ARMV8_IDX_CYCLE_COUNTER)
		value = read_sysreg(pmccntr_el0);
	else if (armv8pmu_select_counter(idx) == idx)
		value = read_sysreg(pmxevcntr_el0);
	else
		value = armv8pmu_read_hw_counter(event);

	return value;
}

static inline void armv8pmu_write_counter(struct perf_event *event, u32 value)
static inline void armv8pmu_write_evcntr(int idx, u32 value)
{
	armv8pmu_select_counter(idx);
	write_sysreg(value, pmxevcntr_el0);
}

static inline void armv8pmu_write_hw_counter(struct perf_event *event,
					     u64 value)
{
	int idx = event->hw.idx;

	if (armv8pmu_event_is_chained(event)) {
		armv8pmu_write_evcntr(idx, upper_32_bits(value));
		armv8pmu_write_evcntr(idx - 1, lower_32_bits(value));
	} else {
		armv8pmu_write_evcntr(idx, value);
	}
}

static inline void armv8pmu_write_counter(struct perf_event *event, u64 value)
{
	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;
@@ -541,23 +597,44 @@ static inline void armv8pmu_write_counter(struct perf_event *event, u32 value)
			smp_processor_id(), idx);
	else if (idx == ARMV8_IDX_CYCLE_COUNTER) {
		/*
		 * Set the upper 32bits as this is a 64bit counter but we only
		 * count using the lower 32bits and we want an interrupt when
		 * it overflows.
		 * The cycles counter is really a 64-bit counter.
		 * When treating it as a 32-bit counter, we only count
		 * the lower 32 bits, and set the upper 32-bits so that
		 * we get an interrupt upon 32-bit overflow.
		 */
		u64 value64 = 0xffffffff00000000ULL | value;

		write_sysreg(value64, pmccntr_el0);
	} else if (armv8pmu_select_counter(idx) == idx)
		write_sysreg(value, pmxevcntr_el0);
		if (!armv8pmu_event_is_64bit(event))
			value |= 0xffffffff00000000ULL;
		write_sysreg(value, pmccntr_el0);
	} else
		armv8pmu_write_hw_counter(event, value);
}

static inline void armv8pmu_write_evtype(int idx, u32 val)
{
	if (armv8pmu_select_counter(idx) == idx) {
	armv8pmu_select_counter(idx);
	val &= ARMV8_PMU_EVTYPE_MASK;
	write_sysreg(val, pmxevtyper_el0);
}

static inline void armv8pmu_write_event_type(struct perf_event *event)
{
	struct hw_perf_event *hwc = &event->hw;
	int idx = hwc->idx;

	/*
	 * For chained events, the low counter is programmed to count
	 * the event of interest and the high counter is programmed
	 * with CHAIN event code with filters set to count at all ELs.
	 */
	if (armv8pmu_event_is_chained(event)) {
		u32 chain_evt = ARMV8_PMUV3_PERFCTR_CHAIN |
				ARMV8_PMU_INCLUDE_EL2;

		armv8pmu_write_evtype(idx - 1, hwc->config_base);
		armv8pmu_write_evtype(idx, chain_evt);
	} else {
		armv8pmu_write_evtype(idx, hwc->config_base);
	}
}

static inline int armv8pmu_enable_counter(int idx)
@@ -567,6 +644,16 @@ static inline int armv8pmu_enable_counter(int idx)
	return idx;
}

static inline void armv8pmu_enable_event_counter(struct perf_event *event)
{
	int idx = event->hw.idx;

	armv8pmu_enable_counter(idx);
	if (armv8pmu_event_is_chained(event))
		armv8pmu_enable_counter(idx - 1);
	isb();
}

static inline int armv8pmu_disable_counter(int idx)
{
	u32 counter = ARMV8_IDX_TO_COUNTER(idx);
@@ -574,6 +661,16 @@ static inline int armv8pmu_disable_counter(int idx)
	return idx;
}

static inline void armv8pmu_disable_event_counter(struct perf_event *event)
{
	struct hw_perf_event *hwc = &event->hw;
	int idx = hwc->idx;

	if (armv8pmu_event_is_chained(event))
		armv8pmu_disable_counter(idx - 1);
	armv8pmu_disable_counter(idx);
}

static inline int armv8pmu_enable_intens(int idx)
{
	u32 counter = ARMV8_IDX_TO_COUNTER(idx);
@@ -581,6 +678,11 @@ static inline int armv8pmu_enable_intens(int idx)
	return idx;
}

static inline int armv8pmu_enable_event_irq(struct perf_event *event)
{
	return armv8pmu_enable_intens(event->hw.idx);
}

static inline int armv8pmu_disable_intens(int idx)
{
	u32 counter = ARMV8_IDX_TO_COUNTER(idx);
@@ -593,6 +695,11 @@ static inline int armv8pmu_disable_intens(int idx)
	return idx;
}

static inline int armv8pmu_disable_event_irq(struct perf_event *event)
{
	return armv8pmu_disable_intens(event->hw.idx);
}

static inline u32 armv8pmu_getreset_flags(void)
{
	u32 value;
@@ -610,10 +717,8 @@ static inline u32 armv8pmu_getreset_flags(void)
static void armv8pmu_enable_event(struct perf_event *event)
{
	unsigned long flags;
	struct hw_perf_event *hwc = &event->hw;
	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
	int idx = hwc->idx;

	/*
	 * Enable counter and interrupt, and set the counter to count
@@ -624,22 +729,22 @@ static void armv8pmu_enable_event(struct perf_event *event)
	/*
	 * Disable counter
	 */
	armv8pmu_disable_counter(idx);
	armv8pmu_disable_event_counter(event);

	/*
	 * Set event (if destined for PMNx counters).
	 */
	armv8pmu_write_evtype(idx, hwc->config_base);
	armv8pmu_write_event_type(event);

	/*
	 * Enable interrupt for this counter
	 */
	armv8pmu_enable_intens(idx);
	armv8pmu_enable_event_irq(event);

	/*
	 * Enable counter
	 */
	armv8pmu_enable_counter(idx);
	armv8pmu_enable_event_counter(event);

	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
@@ -647,10 +752,8 @@ static void armv8pmu_enable_event(struct perf_event *event)
static void armv8pmu_disable_event(struct perf_event *event)
{
	unsigned long flags;
	struct hw_perf_event *hwc = &event->hw;
	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
	int idx = hwc->idx;

	/*
	 * Disable counter and interrupt
@@ -660,13 +763,35 @@ static void armv8pmu_disable_event(struct perf_event *event)
	/*
	 * Disable counter
	 */
	armv8pmu_disable_counter(idx);
	armv8pmu_disable_event_counter(event);

	/*
	 * Disable interrupt for this counter
	 */
	armv8pmu_disable_intens(idx);
	armv8pmu_disable_event_irq(event);

	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}

static void armv8pmu_start(struct arm_pmu *cpu_pmu)
{
	unsigned long flags;
	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);

	raw_spin_lock_irqsave(&events->pmu_lock, flags);
	/* Enable all counters */
	armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E);
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}

static void armv8pmu_stop(struct arm_pmu *cpu_pmu)
{
	unsigned long flags;
	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);

	raw_spin_lock_irqsave(&events->pmu_lock, flags);
	/* Disable all counters */
	armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E);
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}

@@ -694,6 +819,11 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
	 */
	regs = get_irq_regs();

	/*
	 * Stop the PMU while processing the counter overflows
	 * to prevent skews in group events.
	 */
	armv8pmu_stop(cpu_pmu);
	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
		struct perf_event *event = cpuc->events[idx];
		struct hw_perf_event *hwc;
@@ -718,6 +848,7 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
		if (perf_event_overflow(event, &data, regs))
			cpu_pmu->disable(event);
	}
	armv8pmu_start(cpu_pmu);

	/*
	 * Handle the pending perf events.
@@ -731,32 +862,42 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
	return IRQ_HANDLED;
}

static void armv8pmu_start(struct arm_pmu *cpu_pmu)
static int armv8pmu_get_single_idx(struct pmu_hw_events *cpuc,
				    struct arm_pmu *cpu_pmu)
{
	unsigned long flags;
	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
	int idx;

	raw_spin_lock_irqsave(&events->pmu_lock, flags);
	/* Enable all counters */
	armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E);
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
	for (idx = ARMV8_IDX_COUNTER0; idx < cpu_pmu->num_events; idx ++) {
		if (!test_and_set_bit(idx, cpuc->used_mask))
			return idx;
	}
	return -EAGAIN;
}

static void armv8pmu_stop(struct arm_pmu *cpu_pmu)
static int armv8pmu_get_chain_idx(struct pmu_hw_events *cpuc,
				   struct arm_pmu *cpu_pmu)
{
	unsigned long flags;
	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
	int idx;

	raw_spin_lock_irqsave(&events->pmu_lock, flags);
	/* Disable all counters */
	armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E);
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
	/*
	 * Chaining requires two consecutive event counters, where
	 * the lower idx must be even.
	 */
	for (idx = ARMV8_IDX_COUNTER0 + 1; idx < cpu_pmu->num_events; idx += 2) {
		if (!test_and_set_bit(idx, cpuc->used_mask)) {
			/* Check if the preceding even counter is available */
			if (!test_and_set_bit(idx - 1, cpuc->used_mask))
				return idx;
			/* Release the Odd counter */
			clear_bit(idx, cpuc->used_mask);
		}
	}
	return -EAGAIN;
}

static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
				  struct perf_event *event)
{
	int idx;
	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;
	unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT;
@@ -770,13 +911,20 @@ static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
	/*
	 * Otherwise use events counters
	 */
	for (idx = ARMV8_IDX_COUNTER0; idx < cpu_pmu->num_events; ++idx) {
		if (!test_and_set_bit(idx, cpuc->used_mask))
			return idx;
	if (armv8pmu_event_is_64bit(event))
		return	armv8pmu_get_chain_idx(cpuc, cpu_pmu);
	else
		return armv8pmu_get_single_idx(cpuc, cpu_pmu);
}

	/* The counters are all in use. */
	return -EAGAIN;
static void armv8pmu_clear_event_idx(struct pmu_hw_events *cpuc,
				     struct perf_event *event)
{
	int idx = event->hw.idx;

	clear_bit(idx, cpuc->used_mask);
	if (armv8pmu_event_is_chained(event))
		clear_bit(idx - 1, cpuc->used_mask);
}

/*
@@ -851,6 +999,9 @@ static int __armv8_pmuv3_map_event(struct perf_event *event,
				       &armv8_pmuv3_perf_cache_map,
				       ARMV8_PMU_EVTYPE_EVENT);

	if (armv8pmu_event_is_64bit(event))
		event->hw.flags |= ARMPMU_EVT_64BIT;

	/* Onl expose micro/arch events supported by this PMU */
	if ((hw_event_id > 0) && (hw_event_id < ARMV8_PMUV3_MAX_COMMON_EVENTS)
	    && test_bit(hw_event_id, armpmu->pmceid_bitmap)) {
@@ -957,10 +1108,10 @@ static int armv8_pmu_init(struct arm_pmu *cpu_pmu)
	cpu_pmu->read_counter		= armv8pmu_read_counter,
	cpu_pmu->write_counter		= armv8pmu_write_counter,
	cpu_pmu->get_event_idx		= armv8pmu_get_event_idx,
	cpu_pmu->clear_event_idx	= armv8pmu_clear_event_idx,
	cpu_pmu->start			= armv8pmu_start,
	cpu_pmu->stop			= armv8pmu_stop,
	cpu_pmu->reset			= armv8pmu_reset,
	cpu_pmu->max_period		= (1LLU << 32) - 1,
	cpu_pmu->set_event_filter	= armv8pmu_set_event_filter;

	return 0;
+26 −12
Original line number Diff line number Diff line
@@ -53,6 +53,16 @@ enum {
	CCI_IF_MAX,
};

#define NUM_HW_CNTRS_CII_4XX	4
#define NUM_HW_CNTRS_CII_5XX	8
#define NUM_HW_CNTRS_MAX	NUM_HW_CNTRS_CII_5XX

#define FIXED_HW_CNTRS_CII_4XX	1
#define FIXED_HW_CNTRS_CII_5XX	0
#define FIXED_HW_CNTRS_MAX	FIXED_HW_CNTRS_CII_4XX

#define HW_CNTRS_MAX		(NUM_HW_CNTRS_MAX + FIXED_HW_CNTRS_MAX)

struct event_range {
	u32 min;
	u32 max;
@@ -633,8 +643,7 @@ static void cci_pmu_sync_counters(struct cci_pmu *cci_pmu)
{
	int i;
	struct cci_pmu_hw_events *cci_hw = &cci_pmu->hw_events;

	DECLARE_BITMAP(mask, cci_pmu->num_cntrs);
	DECLARE_BITMAP(mask, HW_CNTRS_MAX);

	bitmap_zero(mask, cci_pmu->num_cntrs);
	for_each_set_bit(i, cci_pmu->hw_events.used_mask, cci_pmu->num_cntrs) {
@@ -940,7 +949,7 @@ static void pmu_write_counters(struct cci_pmu *cci_pmu, unsigned long *mask)
static void cci5xx_pmu_write_counters(struct cci_pmu *cci_pmu, unsigned long *mask)
{
	int i;
	DECLARE_BITMAP(saved_mask, cci_pmu->num_cntrs);
	DECLARE_BITMAP(saved_mask, HW_CNTRS_MAX);

	bitmap_zero(saved_mask, cci_pmu->num_cntrs);
	pmu_save_counters(cci_pmu, saved_mask);
@@ -1245,7 +1254,7 @@ static int validate_group(struct perf_event *event)
{
	struct perf_event *sibling, *leader = event->group_leader;
	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
	unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
	unsigned long mask[BITS_TO_LONGS(HW_CNTRS_MAX)];
	struct cci_pmu_hw_events fake_pmu = {
		/*
		 * Initialise the fake PMU. We only need to populate the
@@ -1403,6 +1412,11 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
	char *name = model->name;
	u32 num_cntrs;

	if (WARN_ON(model->num_hw_cntrs > NUM_HW_CNTRS_MAX))
		return -EINVAL;
	if (WARN_ON(model->fixed_hw_cntrs > FIXED_HW_CNTRS_MAX))
		return -EINVAL;

	pmu_event_attr_group.attrs = model->event_attrs;
	pmu_format_attr_group.attrs = model->format_attrs;

@@ -1455,8 +1469,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
#ifdef CONFIG_ARM_CCI400_PMU
	[CCI400_R0] = {
		.name = "CCI_400",
		.fixed_hw_cntrs = 1,	/* Cycle counter */
		.num_hw_cntrs = 4,
		.fixed_hw_cntrs = FIXED_HW_CNTRS_CII_4XX, /* Cycle counter */
		.num_hw_cntrs = NUM_HW_CNTRS_CII_4XX,
		.cntr_size = SZ_4K,
		.format_attrs = cci400_pmu_format_attrs,
		.event_attrs = cci400_r0_pmu_event_attrs,
@@ -1475,8 +1489,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
	},
	[CCI400_R1] = {
		.name = "CCI_400_r1",
		.fixed_hw_cntrs = 1,	/* Cycle counter */
		.num_hw_cntrs = 4,
		.fixed_hw_cntrs = FIXED_HW_CNTRS_CII_4XX, /* Cycle counter */
		.num_hw_cntrs = NUM_HW_CNTRS_CII_4XX,
		.cntr_size = SZ_4K,
		.format_attrs = cci400_pmu_format_attrs,
		.event_attrs = cci400_r1_pmu_event_attrs,
@@ -1497,8 +1511,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
#ifdef CONFIG_ARM_CCI5xx_PMU
	[CCI500_R0] = {
		.name = "CCI_500",
		.fixed_hw_cntrs = 0,
		.num_hw_cntrs = 8,
		.fixed_hw_cntrs = FIXED_HW_CNTRS_CII_5XX,
		.num_hw_cntrs = NUM_HW_CNTRS_CII_5XX,
		.cntr_size = SZ_64K,
		.format_attrs = cci5xx_pmu_format_attrs,
		.event_attrs = cci5xx_pmu_event_attrs,
@@ -1521,8 +1535,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
	},
	[CCI550_R0] = {
		.name = "CCI_550",
		.fixed_hw_cntrs = 0,
		.num_hw_cntrs = 8,
		.fixed_hw_cntrs = FIXED_HW_CNTRS_CII_5XX,
		.num_hw_cntrs = NUM_HW_CNTRS_CII_5XX,
		.cntr_size = SZ_64K,
		.format_attrs = cci5xx_pmu_format_attrs,
		.event_attrs = cci5xx_pmu_event_attrs,
Loading