Commit ba70ffa7 authored by Will Deacon's avatar Will Deacon

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
...@@ -233,7 +233,7 @@ armv6_pmcr_counter_has_overflowed(unsigned long pmcr, ...@@ -233,7 +233,7 @@ armv6_pmcr_counter_has_overflowed(unsigned long pmcr,
return ret; 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; struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx; int counter = hwc->idx;
...@@ -251,7 +251,7 @@ static inline u32 armv6pmu_read_counter(struct perf_event *event) ...@@ -251,7 +251,7 @@ static inline u32 armv6pmu_read_counter(struct perf_event *event)
return value; 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; struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx; int counter = hwc->idx;
...@@ -411,6 +411,12 @@ armv6pmu_get_event_idx(struct pmu_hw_events *cpuc, ...@@ -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) static void armv6pmu_disable_event(struct perf_event *event)
{ {
unsigned long val, mask, evt, flags; unsigned long val, mask, evt, flags;
...@@ -491,11 +497,11 @@ static void armv6pmu_init(struct arm_pmu *cpu_pmu) ...@@ -491,11 +497,11 @@ static void armv6pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->read_counter = armv6pmu_read_counter; cpu_pmu->read_counter = armv6pmu_read_counter;
cpu_pmu->write_counter = armv6pmu_write_counter; cpu_pmu->write_counter = armv6pmu_write_counter;
cpu_pmu->get_event_idx = armv6pmu_get_event_idx; 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->start = armv6pmu_start;
cpu_pmu->stop = armv6pmu_stop; cpu_pmu->stop = armv6pmu_stop;
cpu_pmu->map_event = armv6_map_event; cpu_pmu->map_event = armv6_map_event;
cpu_pmu->num_events = 3; cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
} }
static int armv6_1136_pmu_init(struct arm_pmu *cpu_pmu) 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) ...@@ -542,11 +548,11 @@ static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->read_counter = armv6pmu_read_counter; cpu_pmu->read_counter = armv6pmu_read_counter;
cpu_pmu->write_counter = armv6pmu_write_counter; cpu_pmu->write_counter = armv6pmu_write_counter;
cpu_pmu->get_event_idx = armv6pmu_get_event_idx; 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->start = armv6pmu_start;
cpu_pmu->stop = armv6pmu_stop; cpu_pmu->stop = armv6pmu_stop;
cpu_pmu->map_event = armv6mpcore_map_event; cpu_pmu->map_event = armv6mpcore_map_event;
cpu_pmu->num_events = 3; cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
return 0; return 0;
} }
......
...@@ -743,7 +743,7 @@ static inline void armv7_pmnc_select_counter(int idx) ...@@ -743,7 +743,7 @@ static inline void armv7_pmnc_select_counter(int idx)
isb(); 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 arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
...@@ -763,7 +763,7 @@ static inline u32 armv7pmu_read_counter(struct perf_event *event) ...@@ -763,7 +763,7 @@ static inline u32 armv7pmu_read_counter(struct perf_event *event)
return value; 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 arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
...@@ -1058,6 +1058,12 @@ static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc, ...@@ -1058,6 +1058,12 @@ static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc,
return -EAGAIN; 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. * 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) ...@@ -1167,10 +1173,10 @@ static void armv7pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->read_counter = armv7pmu_read_counter; cpu_pmu->read_counter = armv7pmu_read_counter;
cpu_pmu->write_counter = armv7pmu_write_counter; cpu_pmu->write_counter = armv7pmu_write_counter;
cpu_pmu->get_event_idx = armv7pmu_get_event_idx; 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->start = armv7pmu_start;
cpu_pmu->stop = armv7pmu_stop; cpu_pmu->stop = armv7pmu_stop;
cpu_pmu->reset = armv7pmu_reset; cpu_pmu->reset = armv7pmu_reset;
cpu_pmu->max_period = (1LLU << 32) - 1;
}; };
static void armv7_read_num_pmnc_events(void *info) 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, ...@@ -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 venum_event = EVENT_VENUM(hwc->config_base);
bool krait_event = EVENT_CPU(hwc->config_base); bool krait_event = EVENT_CPU(hwc->config_base);
armv7pmu_clear_event_idx(cpuc, event);
if (venum_event || krait_event) { if (venum_event || krait_event) {
bit = krait_event_to_bit(event, region, group); bit = krait_event_to_bit(event, region, group);
clear_bit(bit, cpuc->used_mask); clear_bit(bit, cpuc->used_mask);
...@@ -1967,6 +1974,7 @@ static void scorpion_pmu_clear_event_idx(struct pmu_hw_events *cpuc, ...@@ -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 venum_event = EVENT_VENUM(hwc->config_base);
bool scorpion_event = EVENT_CPU(hwc->config_base); bool scorpion_event = EVENT_CPU(hwc->config_base);
armv7pmu_clear_event_idx(cpuc, event);
if (venum_event || scorpion_event) { if (venum_event || scorpion_event) {
bit = scorpion_event_to_bit(event, region, group); bit = scorpion_event_to_bit(event, region, group);
clear_bit(bit, cpuc->used_mask); clear_bit(bit, cpuc->used_mask);
...@@ -2030,6 +2038,7 @@ static struct platform_driver armv7_pmu_driver = { ...@@ -2030,6 +2038,7 @@ static struct platform_driver armv7_pmu_driver = {
.driver = { .driver = {
.name = "armv7-pmu", .name = "armv7-pmu",
.of_match_table = armv7_pmu_of_device_ids, .of_match_table = armv7_pmu_of_device_ids,
.suppress_bind_attrs = true,
}, },
.probe = armv7_pmu_device_probe, .probe = armv7_pmu_device_probe,
}; };
......
...@@ -292,6 +292,12 @@ xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc, ...@@ -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) static void xscale1pmu_start(struct arm_pmu *cpu_pmu)
{ {
unsigned long flags, val; unsigned long flags, val;
...@@ -316,7 +322,7 @@ static void xscale1pmu_stop(struct arm_pmu *cpu_pmu) ...@@ -316,7 +322,7 @@ static void xscale1pmu_stop(struct arm_pmu *cpu_pmu)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 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; struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx; int counter = hwc->idx;
...@@ -337,7 +343,7 @@ static inline u32 xscale1pmu_read_counter(struct perf_event *event) ...@@ -337,7 +343,7 @@ static inline u32 xscale1pmu_read_counter(struct perf_event *event)
return val; 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; struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx; int counter = hwc->idx;
...@@ -370,11 +376,11 @@ static int xscale1pmu_init(struct arm_pmu *cpu_pmu) ...@@ -370,11 +376,11 @@ static int xscale1pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->read_counter = xscale1pmu_read_counter; cpu_pmu->read_counter = xscale1pmu_read_counter;
cpu_pmu->write_counter = xscale1pmu_write_counter; cpu_pmu->write_counter = xscale1pmu_write_counter;
cpu_pmu->get_event_idx = xscale1pmu_get_event_idx; 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->start = xscale1pmu_start;
cpu_pmu->stop = xscale1pmu_stop; cpu_pmu->stop = xscale1pmu_stop;
cpu_pmu->map_event = xscale_map_event; cpu_pmu->map_event = xscale_map_event;
cpu_pmu->num_events = 3; cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
return 0; return 0;
} }
...@@ -679,7 +685,7 @@ static void xscale2pmu_stop(struct arm_pmu *cpu_pmu) ...@@ -679,7 +685,7 @@ static void xscale2pmu_stop(struct arm_pmu *cpu_pmu)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 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; struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx; int counter = hwc->idx;
...@@ -706,7 +712,7 @@ static inline u32 xscale2pmu_read_counter(struct perf_event *event) ...@@ -706,7 +712,7 @@ static inline u32 xscale2pmu_read_counter(struct perf_event *event)
return val; 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; struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx; int counter = hwc->idx;
...@@ -739,11 +745,11 @@ static int xscale2pmu_init(struct arm_pmu *cpu_pmu) ...@@ -739,11 +745,11 @@ static int xscale2pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->read_counter = xscale2pmu_read_counter; cpu_pmu->read_counter = xscale2pmu_read_counter;
cpu_pmu->write_counter = xscale2pmu_write_counter; cpu_pmu->write_counter = xscale2pmu_write_counter;
cpu_pmu->get_event_idx = xscale2pmu_get_event_idx; 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->start = xscale2pmu_start;
cpu_pmu->stop = xscale2pmu_stop; cpu_pmu->stop = xscale2pmu_stop;
cpu_pmu->map_event = xscale_map_event; cpu_pmu->map_event = xscale_map_event;
cpu_pmu->num_events = 5; cpu_pmu->num_events = 5;
cpu_pmu->max_period = (1LLU << 32) - 1;
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -53,6 +53,16 @@ enum { ...@@ -53,6 +53,16 @@ enum {
CCI_IF_MAX, 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 { struct event_range {
u32 min; u32 min;
u32 max; u32 max;
...@@ -633,8 +643,7 @@ static void cci_pmu_sync_counters(struct cci_pmu *cci_pmu) ...@@ -633,8 +643,7 @@ static void cci_pmu_sync_counters(struct cci_pmu *cci_pmu)
{ {
int i; int i;
struct cci_pmu_hw_events *cci_hw = &cci_pmu->hw_events; struct cci_pmu_hw_events *cci_hw = &cci_pmu->hw_events;
DECLARE_BITMAP(mask, HW_CNTRS_MAX);
DECLARE_BITMAP(mask, cci_pmu->num_cntrs);
bitmap_zero(mask, cci_pmu->num_cntrs); bitmap_zero(mask, cci_pmu->num_cntrs);
for_each_set_bit(i, cci_pmu->hw_events.used_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) ...@@ -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) static void cci5xx_pmu_write_counters(struct cci_pmu *cci_pmu, unsigned long *mask)
{ {
int i; 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); bitmap_zero(saved_mask, cci_pmu->num_cntrs);
pmu_save_counters(cci_pmu, saved_mask); pmu_save_counters(cci_pmu, saved_mask);
...@@ -1245,7 +1254,7 @@ static int validate_group(struct perf_event *event) ...@@ -1245,7 +1254,7 @@ static int validate_group(struct perf_event *event)
{ {
struct perf_event *sibling, *leader = event->group_leader; struct perf_event *sibling, *leader = event->group_leader;
struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu); 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 = { struct cci_pmu_hw_events fake_pmu = {
/* /*
* Initialise the fake PMU. We only need to populate the * 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) ...@@ -1403,6 +1412,11 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
char *name = model->name; char *name = model->name;
u32 num_cntrs; 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_event_attr_group.attrs = model->event_attrs;
pmu_format_attr_group.attrs = model->format_attrs; pmu_format_attr_group.attrs = model->format_attrs;
...@@ -1455,8 +1469,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = { ...@@ -1455,8 +1469,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
#ifdef CONFIG_ARM_CCI400_PMU #ifdef CONFIG_ARM_CCI400_PMU
[CCI400_R0] = { [CCI400_R0] = {
.name = "CCI_400", .name = "CCI_400",
.fixed_hw_cntrs = 1, /* Cycle counter */ .fixed_hw_cntrs = FIXED_HW_CNTRS_CII_4XX, /* Cycle counter */
.num_hw_cntrs = 4, .num_hw_cntrs = NUM_HW_CNTRS_CII_4XX,
.cntr_size = SZ_4K, .cntr_size = SZ_4K,
.format_attrs = cci400_pmu_format_attrs, .format_attrs = cci400_pmu_format_attrs,
.event_attrs = cci400_r0_pmu_event_attrs, .event_attrs = cci400_r0_pmu_event_attrs,
...@@ -1475,8 +1489,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = { ...@@ -1475,8 +1489,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
}, },
[CCI400_R1] = { [CCI400_R1] = {
.name = "CCI_400_r1", .name = "CCI_400_r1",
.fixed_hw_cntrs = 1, /* Cycle counter */ .fixed_hw_cntrs = FIXED_HW_CNTRS_CII_4XX, /* Cycle counter */
.num_hw_cntrs = 4, .num_hw_cntrs = NUM_HW_CNTRS_CII_4XX,
.cntr_size = SZ_4K, .cntr_size = SZ_4K,
.format_attrs = cci400_pmu_format_attrs, .format_attrs = cci400_pmu_format_attrs,
.event_attrs = cci400_r1_pmu_event_attrs, .event_attrs = cci400_r1_pmu_event_attrs,
...@@ -1497,8 +1511,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = { ...@@ -1497,8 +1511,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
#ifdef CONFIG_ARM_CCI5xx_PMU #ifdef CONFIG_ARM_CCI5xx_PMU
[CCI500_R0] = { [CCI500_R0] = {
.name = "CCI_500", .name = "CCI_500",
.fixed_hw_cntrs = 0, .fixed_hw_cntrs = FIXED_HW_CNTRS_CII_5XX,
.num_hw_cntrs = 8, .num_hw_cntrs = NUM_HW_CNTRS_CII_5XX,
.cntr_size = SZ_64K, .cntr_size = SZ_64K,
.format_attrs = cci5xx_pmu_format_attrs, .format_attrs = cci5xx_pmu_format_attrs,
.event_attrs = cci5xx_pmu_event_attrs, .event_attrs = cci5xx_pmu_event_attrs,
...@@ -1521,8 +1535,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = { ...@@ -1521,8 +1535,8 @@ static __maybe_unused struct cci_pmu_model cci_pmu_models[] = {
}, },
[CCI550_R0] = { [CCI550_R0] = {
.name = "CCI_550", .name = "CCI_550",
.fixed_hw_cntrs = 0, .fixed_hw_cntrs = FIXED_HW_CNTRS_CII_5XX,
.num_hw_cntrs = 8, .num_hw_cntrs = NUM_HW_CNTRS_CII_5XX,
.cntr_size = SZ_64K, .cntr_size = SZ_64K,
.format_attrs = cci5xx_pmu_format_attrs, .format_attrs = cci5xx_pmu_format_attrs,
.event_attrs = cci5xx_pmu_event_attrs, .event_attrs = cci5xx_pmu_event_attrs,
......
...@@ -1485,17 +1485,9 @@ static int arm_ccn_probe(struct platform_device *pdev) ...@@ -1485,17 +1485,9 @@ static int arm_ccn_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ccn); platform_set_drvdata(pdev, ccn);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) ccn->base = devm_ioremap_resource(ccn->dev, res);
return -EINVAL; if (IS_ERR(ccn->base))
return PTR_ERR(ccn->base);
if (!devm_request_mem_region(ccn->dev, res->start,
resource_size(res), pdev->name))
return -EBUSY;
ccn->base = devm_ioremap(ccn->dev, res->start,
resource_size(res));
if (!ccn->base)
return -EFAULT;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) if (!res)
......
...@@ -28,6 +28,14 @@ ...@@ -28,6 +28,14 @@
static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu); static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu);
static DEFINE_PER_CPU(int, cpu_irq); static DEFINE_PER_CPU(int, cpu_irq);
static inline u64 arm_pmu_event_max_period(struct perf_event *event)
{
if (event->hw.flags & ARMPMU_EVT_64BIT)
return GENMASK_ULL(63, 0);
else
return GENMASK_ULL(31, 0);
}
static int static int
armpmu_map_cache_event(const unsigned (*cache_map) armpmu_map_cache_event(const unsigned (*cache_map)
[PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_MAX]
...@@ -114,8 +122,10 @@ int armpmu_event_set_period(struct perf_event *event) ...@@ -114,8 +122,10 @@ int armpmu_event_set_period(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
s64 left = local64_read(&hwc->period_left); s64 left = local64_read(&hwc->period_left);
s64 period = hwc->sample_period; s64 period = hwc->sample_period;
u64 max_period;
int ret = 0; int ret = 0;
max_period = arm_pmu_event_max_period(event);
if (unlikely(left <= -period)) { if (unlikely(left <= -period)) {
left = period; left = period;
local64_set(&hwc->period_left, left); local64_set(&hwc->period_left, left);
...@@ -136,12 +146,12 @@ int armpmu_event_set_period(struct perf_event *event) ...@@ -136,12 +146,12 @@ int armpmu_event_set_period(struct perf_event *event)
* effect we are reducing max_period to account for * effect we are reducing max_period to account for
* interrupt latency (and we are being very conservative). * interrupt latency (and we are being very conservative).
*/ */
if (left > (armpmu->max_period >> 1)) if (left > (max_period >> 1))
left = armpmu->max_period >> 1; left = (max_period >> 1);
local64_set(&hwc->prev_count, (u64)-left); local64_set(&hwc->prev_count, (u64)-left);
armpmu->write_counter(event, (u64)(-left) & 0xffffffff); armpmu->write_counter(event, (u64)(-left) & max_period);
perf_event_update_userpage(event); perf_event_update_userpage(event);
...@@ -153,6 +163,7 @@ u64 armpmu_event_update(struct perf_event *event) ...@@ -153,6 +163,7 @@ u64 armpmu_event_update(struct perf_event *event)
struct arm_pmu *armpmu = to_arm_pmu(event->pmu); struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
u64 delta, prev_raw_count, new_raw_count; u64 delta, prev_raw_count, new_raw_count;
u64 max_period = arm_pmu_event_max_period(event);
again: again:
prev_raw_count = local64_read(&hwc->prev_count); prev_raw_count = local64_read(&hwc->prev_count);
...@@ -162,7 +173,7 @@ u64 armpmu_event_update(struct perf_event *event) ...@@ -162,7 +173,7 @@ u64 armpmu_event_update(struct perf_event *event)
new_raw_count) != prev_raw_count) new_raw_count) != prev_raw_count)
goto again; goto again;
delta = (new_raw_count - prev_raw_count) & armpmu->max_period; delta = (new_raw_count - prev_raw_count) & max_period;
local64_add(delta, &event->count); local64_add(delta, &event->count);
local64_sub(delta, &hwc->period_left); local64_sub(delta, &hwc->period_left);
...@@ -227,11 +238,10 @@ armpmu_del(struct perf_event *event, int flags) ...@@ -227,11 +238,10 @@ armpmu_del(struct perf_event *event, int flags)
armpmu_stop(event, PERF_EF_UPDATE); armpmu_stop(event, PERF_EF_UPDATE);
hw_events->events[idx] = NULL; hw_events->events[idx] = NULL;
clear_bit(idx, hw_events->used_mask); armpmu->clear_event_idx(hw_events, event);
if (armpmu->clear_event_idx)
armpmu->clear_event_idx(hw_events, event);
perf_event_update_userpage(event); perf_event_update_userpage(event);
/* Clear the allocated counter */
hwc->idx = -1;
} }
static int static int
...@@ -360,6 +370,7 @@ __hw_perf_event_init(struct perf_event *event) ...@@ -360,6 +370,7 @@ __hw_perf_event_init(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
int mapping; int mapping;
hwc->flags = 0;
mapping = armpmu->map_event(event); mapping = armpmu->map_event(event);
if (mapping < 0) { if (mapping < 0) {
...@@ -402,7 +413,7 @@ __hw_perf_event_init(struct perf_event *event) ...@@ -402,7 +413,7 @@ __hw_perf_event_init(struct perf_event *event)
* is far less likely to overtake the previous one unless * is far less likely to overtake the previous one unless
* you have some serious IRQ latency issues. * you have some serious IRQ latency issues.
*/ */
hwc->sample_period = armpmu->max_period >> 1; hwc->sample_period = arm_pmu_event_max_period(event) >> 1;
hwc->last_period = hwc->sample_period; hwc->last_period = hwc->sample_period;
local64_set(&hwc->period_left, hwc->sample_period); local64_set(&hwc->period_left, hwc->sample_period);
} }
...@@ -654,14 +665,9 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd) ...@@ -654,14 +665,9 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
int idx; int idx;
for (idx = 0; idx < armpmu->num_events; idx++) { for (idx = 0; idx < armpmu->num_events; idx++) {
/*
* If the counter is not used skip it, there is no
* need of stopping/restarting it.
*/
if (!test_bit(idx, hw_events->used_mask))
continue;
event = hw_events->events[idx]; event = hw_events->events[idx];
if (!event)
continue;
switch (cmd) { switch (cmd) {
case CPU_PM_ENTER: case CPU_PM_ENTER:
......
...@@ -160,7 +160,7 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) ...@@ -160,7 +160,7 @@ static int pmu_parse_irqs(struct arm_pmu *pmu)
static int armpmu_request_irqs(struct arm_pmu *armpmu) static int armpmu_request_irqs(struct arm_pmu *armpmu)
{ {
struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;
int cpu, err; int cpu, err = 0;
for_each_cpu(cpu, &armpmu->supported_cpus) { for_each_cpu(cpu, &armpmu->supported_cpus) {
int irq = per_cpu(hw_events->irq, cpu); int irq = per_cpu(hw_events->irq, cpu);
......
...@@ -350,19 +350,21 @@ void hisi_uncore_pmu_disable(struct pmu *pmu) ...@@ -350,19 +350,21 @@ void hisi_uncore_pmu_disable(struct pmu *pmu)
/* /*
* Read Super CPU cluster and CPU cluster ID from MPIDR_EL1. * Read Super CPU cluster and CPU cluster ID from MPIDR_EL1.
* If multi-threading is supported, SCCL_ID is in MPIDR[aff3] and CCL_ID * If multi-threading is supported, CCL_ID is the low 3-bits in MPIDR[Aff2]
* is in MPIDR[aff2]; if not, SCCL_ID is in MPIDR[aff2] and CCL_ID is * and SCCL_ID is the upper 5-bits of Aff2 field; if not, SCCL_ID
* in MPIDR[aff1]. If this changes in future, this shall be updated. * is in MPIDR[Aff2] and CCL_ID is in MPIDR[Aff1].
*/ */
static void hisi_read_sccl_and_ccl_id(int *sccl_id, int *ccl_id) static void hisi_read_sccl_and_ccl_id(int *sccl_id, int *ccl_id)
{ {
u64 mpidr = read_cpuid_mpidr(); u64 mpidr = read_cpuid_mpidr();
if (mpidr & MPIDR_MT_BITMASK) { if (mpidr & MPIDR_MT_BITMASK) {
int aff2 = MPIDR_AFFINITY_LEVEL(mpidr, 2);
if (sccl_id) if (sccl_id)
*sccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 3); *sccl_id = aff2 >> 3;
if (ccl_id) if (ccl_id)
*ccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 2); *ccl_id = aff2 & 0x7;
} else { } else {
if (sccl_id) if (sccl_id)
*sccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 2); *sccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
......
...@@ -25,6 +25,12 @@ ...@@ -25,6 +25,12 @@
*/ */
#define ARMPMU_MAX_HWEVENTS 32 #define ARMPMU_MAX_HWEVENTS 32
/*
* ARM PMU hw_event flags
*/
/* Event uses a 64bit counter */
#define ARMPMU_EVT_64BIT 1
#define HW_OP_UNSUPPORTED 0xFFFF #define HW_OP_UNSUPPORTED 0xFFFF
#define C(_x) PERF_COUNT_HW_CACHE_##_x #define C(_x) PERF_COUNT_HW_CACHE_##_x
#define CACHE_OP_UNSUPPORTED 0xFFFF #define CACHE_OP_UNSUPPORTED 0xFFFF
...@@ -87,14 +93,13 @@ struct arm_pmu { ...@@ -87,14 +93,13 @@ struct arm_pmu {
struct perf_event *event); struct perf_event *event);
int (*set_event_filter)(struct hw_perf_event *evt, int (*set_event_filter)(struct hw_perf_event *evt,
struct perf_event_attr *attr); struct perf_event_attr *attr);
u32 (*read_counter)(struct perf_event *event); u64 (*read_counter)(struct perf_event *event);
void (*write_counter)(struct perf_event *event, u32 val); void (*write_counter)(struct perf_event *event, u64 val);
void (*start)(struct arm_pmu *); void (*start)(struct arm_pmu *);
void (*stop)(struct arm_pmu *); void (*stop)(struct arm_pmu *);
void (*reset)(void *); void (*reset)(void *);
int (*map_event)(struct perf_event *event); int (*map_event)(struct perf_event *event);
int num_events; int num_events;
u64 max_period;
bool secure_access; /* 32-bit ARM only */ bool secure_access; /* 32-bit ARM only */
#define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40 #define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40
DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS); DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment