Commit cb877710 authored by Catalin Marinas's avatar Catalin Marinas

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

- perf/arm-cci: allow building as module

- perf/arm-ccn: demote dev_warn() to dev_dbg() in event_init()

- miscellaneous perf/arm cleanups

* 'for-next/perf' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux:
  ARM: mcpm, perf/arm-cci: export mcpm_is_available
  drivers/bus: arm-cci: fix build warnings
  drivers/perf: Remove ARM_SPE_PMU explicit PERF_EVENTS dependency
  drivers/perf: arm-ccn: don't log to dmesg in event_init
  perf/arm-cci: Allow building as a module
  perf/arm-cci: Remove pointless PMU disabling
  perf/arm-cc*: Fix MODULE_LICENSE() tags
  arm_pmu: simplify arm_pmu::handle_irq
  perf/arm-cci: Remove unnecessary period adjustment
  perf: simplify getting .drvdata
parents 5d81f7dc 73acc031
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/export.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irqflags.h> #include <linux/irqflags.h>
...@@ -174,6 +175,7 @@ bool mcpm_is_available(void) ...@@ -174,6 +175,7 @@ bool mcpm_is_available(void)
{ {
return (platform_ops) ? true : false; return (platform_ops) ? true : false;
} }
EXPORT_SYMBOL_GPL(mcpm_is_available);
/* /*
* We can't use regular spinlocks. In the switcher case, it is possible * We can't use regular spinlocks. In the switcher case, it is possible
......
...@@ -303,12 +303,10 @@ static void armv6pmu_enable_event(struct perf_event *event) ...@@ -303,12 +303,10 @@ static void armv6pmu_enable_event(struct perf_event *event)
} }
static irqreturn_t static irqreturn_t
armv6pmu_handle_irq(int irq_num, armv6pmu_handle_irq(struct arm_pmu *cpu_pmu)
void *dev)
{ {
unsigned long pmcr = armv6_pmcr_read(); unsigned long pmcr = armv6_pmcr_read();
struct perf_sample_data data; struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
......
...@@ -946,11 +946,10 @@ static void armv7pmu_disable_event(struct perf_event *event) ...@@ -946,11 +946,10 @@ static void armv7pmu_disable_event(struct perf_event *event)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) static irqreturn_t armv7pmu_handle_irq(struct arm_pmu *cpu_pmu)
{ {
u32 pmnc; u32 pmnc;
struct perf_sample_data data; struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
......
...@@ -142,11 +142,10 @@ xscale1_pmnc_counter_has_overflowed(unsigned long pmnc, ...@@ -142,11 +142,10 @@ xscale1_pmnc_counter_has_overflowed(unsigned long pmnc,
} }
static irqreturn_t static irqreturn_t
xscale1pmu_handle_irq(int irq_num, void *dev) xscale1pmu_handle_irq(struct arm_pmu *cpu_pmu)
{ {
unsigned long pmnc; unsigned long pmnc;
struct perf_sample_data data; struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
...@@ -489,11 +488,10 @@ xscale2_pmnc_counter_has_overflowed(unsigned long of_flags, ...@@ -489,11 +488,10 @@ xscale2_pmnc_counter_has_overflowed(unsigned long of_flags,
} }
static irqreturn_t static irqreturn_t
xscale2pmu_handle_irq(int irq_num, void *dev) xscale2pmu_handle_irq(struct arm_pmu *cpu_pmu)
{ {
unsigned long pmnc, of_flags; unsigned long pmnc, of_flags;
struct perf_sample_data data; struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
......
...@@ -670,11 +670,10 @@ static void armv8pmu_disable_event(struct perf_event *event) ...@@ -670,11 +670,10 @@ static void armv8pmu_disable_event(struct perf_event *event)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev) static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
{ {
u32 pmovsr; u32 pmovsr;
struct perf_sample_data data; struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
......
...@@ -6,30 +6,32 @@ menu "Performance monitor support" ...@@ -6,30 +6,32 @@ menu "Performance monitor support"
depends on PERF_EVENTS depends on PERF_EVENTS
config ARM_CCI_PMU config ARM_CCI_PMU
bool tristate "ARM CCI PMU driver"
depends on (ARM && CPU_V7) || ARM64
select ARM_CCI select ARM_CCI
help
Support for PMU events monitoring on the ARM CCI (Cache Coherent
Interconnect) family of products.
If compiled as a module, it will be called arm-cci.
config ARM_CCI400_PMU config ARM_CCI400_PMU
bool "ARM CCI400 PMU support" bool "support CCI-400"
depends on (ARM && CPU_V7) || ARM64 default y
depends on ARM_CCI_PMU
select ARM_CCI400_COMMON select ARM_CCI400_COMMON
select ARM_CCI_PMU
help help
Support for PMU events monitoring on the ARM CCI-400 (cache coherent CCI-400 provides 4 independent event counters counting events related
interconnect). CCI-400 supports counting events related to the to the connected slave/master interfaces, plus a cycle counter.
connected slave/master interfaces.
config ARM_CCI5xx_PMU config ARM_CCI5xx_PMU
bool "ARM CCI-500/CCI-550 PMU support" bool "support CCI-500/CCI-550"
depends on (ARM && CPU_V7) || ARM64 default y
select ARM_CCI_PMU depends on ARM_CCI_PMU
help help
Support for PMU events monitoring on the ARM CCI-500/CCI-550 cache CCI-500/CCI-550 both provide 8 independent event counters, which can
coherent interconnects. Both of them provide 8 independent event counters, count events pertaining to the slave/master interfaces as well as the
which can count events pertaining to the slave/master interfaces as well internal events to the CCI.
as the internal events to the CCI.
If unsure, say Y
config ARM_CCN config ARM_CCN
tristate "ARM CCN driver support" tristate "ARM CCN driver support"
...@@ -94,7 +96,7 @@ config XGENE_PMU ...@@ -94,7 +96,7 @@ config XGENE_PMU
config ARM_SPE_PMU config ARM_SPE_PMU
tristate "Enable support for the ARMv8.2 Statistical Profiling Extension" tristate "Enable support for the ARMv8.2 Statistical Profiling Extension"
depends on PERF_EVENTS && ARM64 depends on ARM64
help help
Enable perf support for the ARMv8.2 Statistical Profiling Enable perf support for the ARMv8.2 Statistical Profiling
Extension, which provides periodic sampling of operations in Extension, which provides periodic sampling of operations in
......
...@@ -120,9 +120,9 @@ enum cci_models { ...@@ -120,9 +120,9 @@ enum cci_models {
static void pmu_write_counters(struct cci_pmu *cci_pmu, static void pmu_write_counters(struct cci_pmu *cci_pmu,
unsigned long *mask); unsigned long *mask);
static ssize_t cci_pmu_format_show(struct device *dev, static ssize_t __maybe_unused cci_pmu_format_show(struct device *dev,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
static ssize_t cci_pmu_event_show(struct device *dev, static ssize_t __maybe_unused cci_pmu_event_show(struct device *dev,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \ #define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
...@@ -1184,16 +1184,11 @@ static int cci_pmu_add(struct perf_event *event, int flags) ...@@ -1184,16 +1184,11 @@ static int cci_pmu_add(struct perf_event *event, int flags)
struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events; struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
int idx; int idx;
int err = 0;
perf_pmu_disable(event->pmu);
/* If we don't have a space for the counter then finish early. */ /* If we don't have a space for the counter then finish early. */
idx = pmu_get_event_idx(hw_events, event); idx = pmu_get_event_idx(hw_events, event);
if (idx < 0) { if (idx < 0)
err = idx; return idx;
goto out;
}
event->hw.idx = idx; event->hw.idx = idx;
hw_events->events[idx] = event; hw_events->events[idx] = event;
...@@ -1205,9 +1200,7 @@ static int cci_pmu_add(struct perf_event *event, int flags) ...@@ -1205,9 +1200,7 @@ static int cci_pmu_add(struct perf_event *event, int flags)
/* Propagate our changes to the userspace mapping. */ /* Propagate our changes to the userspace mapping. */
perf_event_update_userpage(event); perf_event_update_userpage(event);
out: return 0;
perf_pmu_enable(event->pmu);
return err;
} }
static void cci_pmu_del(struct perf_event *event, int flags) static void cci_pmu_del(struct perf_event *event, int flags)
...@@ -1304,15 +1297,6 @@ static int __hw_perf_event_init(struct perf_event *event) ...@@ -1304,15 +1297,6 @@ static int __hw_perf_event_init(struct perf_event *event)
*/ */
hwc->config_base |= (unsigned long)mapping; hwc->config_base |= (unsigned long)mapping;
/*
* Limit the sample_period to half of the counter width. That way, the
* new counter value is far less likely to overtake the previous one
* unless you have some serious IRQ latency issues.
*/
hwc->sample_period = CCI_PMU_CNTR_MASK >> 1;
hwc->last_period = hwc->sample_period;
local64_set(&hwc->period_left, hwc->sample_period);
if (event->group_leader != event) { if (event->group_leader != event) {
if (validate_group(event) != 0) if (validate_group(event) != 0)
return -EINVAL; return -EINVAL;
...@@ -1423,6 +1407,7 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev) ...@@ -1423,6 +1407,7 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
pmu_format_attr_group.attrs = model->format_attrs; pmu_format_attr_group.attrs = model->format_attrs;
cci_pmu->pmu = (struct pmu) { cci_pmu->pmu = (struct pmu) {
.module = THIS_MODULE,
.name = cci_pmu->model->name, .name = cci_pmu->model->name,
.task_ctx_nr = perf_invalid_context, .task_ctx_nr = perf_invalid_context,
.pmu_enable = cci_pmu_enable, .pmu_enable = cci_pmu_enable,
...@@ -1466,7 +1451,7 @@ static int cci_pmu_offline_cpu(unsigned int cpu) ...@@ -1466,7 +1451,7 @@ static int cci_pmu_offline_cpu(unsigned int cpu)
return 0; return 0;
} }
static struct cci_pmu_model cci_pmu_models[] = { 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",
...@@ -1588,6 +1573,7 @@ static const struct of_device_id arm_cci_pmu_matches[] = { ...@@ -1588,6 +1573,7 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
#endif #endif
{}, {},
}; };
MODULE_DEVICE_TABLE(of, arm_cci_pmu_matches);
static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs) static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
{ {
...@@ -1709,14 +1695,27 @@ static int cci_pmu_probe(struct platform_device *pdev) ...@@ -1709,14 +1695,27 @@ static int cci_pmu_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int cci_pmu_remove(struct platform_device *pdev)
{
if (!g_cci_pmu)
return 0;
cpuhp_remove_state(CPUHP_AP_PERF_ARM_CCI_ONLINE);
perf_pmu_unregister(&g_cci_pmu->pmu);
g_cci_pmu = NULL;
return 0;
}
static struct platform_driver cci_pmu_driver = { static struct platform_driver cci_pmu_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = arm_cci_pmu_matches, .of_match_table = arm_cci_pmu_matches,
}, },
.probe = cci_pmu_probe, .probe = cci_pmu_probe,
.remove = cci_pmu_remove,
}; };
builtin_platform_driver(cci_pmu_driver); module_platform_driver(cci_pmu_driver);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ARM CCI PMU support"); MODULE_DESCRIPTION("ARM CCI PMU support");
...@@ -736,7 +736,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) ...@@ -736,7 +736,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
ccn = pmu_to_arm_ccn(event->pmu); ccn = pmu_to_arm_ccn(event->pmu);
if (hw->sample_period) { if (hw->sample_period) {
dev_warn(ccn->dev, "Sampling not supported!\n"); dev_dbg(ccn->dev, "Sampling not supported!\n");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -744,12 +744,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) ...@@ -744,12 +744,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
event->attr.exclude_kernel || event->attr.exclude_hv || event->attr.exclude_kernel || event->attr.exclude_hv ||
event->attr.exclude_idle || event->attr.exclude_host || event->attr.exclude_idle || event->attr.exclude_host ||
event->attr.exclude_guest) { event->attr.exclude_guest) {
dev_warn(ccn->dev, "Can't exclude execution levels!\n"); dev_dbg(ccn->dev, "Can't exclude execution levels!\n");
return -EINVAL; return -EINVAL;
} }
if (event->cpu < 0) { if (event->cpu < 0) {
dev_warn(ccn->dev, "Can't provide per-task data!\n"); dev_dbg(ccn->dev, "Can't provide per-task data!\n");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
/* /*
...@@ -771,13 +771,13 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) ...@@ -771,13 +771,13 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
switch (type) { switch (type) {
case CCN_TYPE_MN: case CCN_TYPE_MN:
if (node_xp != ccn->mn_id) { if (node_xp != ccn->mn_id) {
dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp); dev_dbg(ccn->dev, "Invalid MN ID %d!\n", node_xp);
return -EINVAL; return -EINVAL;
} }
break; break;
case CCN_TYPE_XP: case CCN_TYPE_XP:
if (node_xp >= ccn->num_xps) { if (node_xp >= ccn->num_xps) {
dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp); dev_dbg(ccn->dev, "Invalid XP ID %d!\n", node_xp);
return -EINVAL; return -EINVAL;
} }
break; break;
...@@ -785,11 +785,11 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) ...@@ -785,11 +785,11 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
break; break;
default: default:
if (node_xp >= ccn->num_nodes) { if (node_xp >= ccn->num_nodes) {
dev_warn(ccn->dev, "Invalid node ID %d!\n", node_xp); dev_dbg(ccn->dev, "Invalid node ID %d!\n", node_xp);
return -EINVAL; return -EINVAL;
} }
if (!arm_ccn_pmu_type_eq(type, ccn->node[node_xp].type)) { if (!arm_ccn_pmu_type_eq(type, ccn->node[node_xp].type)) {
dev_warn(ccn->dev, "Invalid type 0x%x for node %d!\n", dev_dbg(ccn->dev, "Invalid type 0x%x for node %d!\n",
type, node_xp); type, node_xp);
return -EINVAL; return -EINVAL;
} }
...@@ -808,19 +808,19 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) ...@@ -808,19 +808,19 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
if (event_id != e->event) if (event_id != e->event)
continue; continue;
if (e->num_ports && port >= e->num_ports) { if (e->num_ports && port >= e->num_ports) {
dev_warn(ccn->dev, "Invalid port %d for node/XP %d!\n", dev_dbg(ccn->dev, "Invalid port %d for node/XP %d!\n",
port, node_xp); port, node_xp);
return -EINVAL; return -EINVAL;
} }
if (e->num_vcs && vc >= e->num_vcs) { if (e->num_vcs && vc >= e->num_vcs) {
dev_warn(ccn->dev, "Invalid vc %d for node/XP %d!\n", dev_dbg(ccn->dev, "Invalid vc %d for node/XP %d!\n",
vc, node_xp); vc, node_xp);
return -EINVAL; return -EINVAL;
} }
valid = 1; valid = 1;
} }
if (!valid) { if (!valid) {
dev_warn(ccn->dev, "Invalid event 0x%x for node/XP %d!\n", dev_dbg(ccn->dev, "Invalid event 0x%x for node/XP %d!\n",
event_id, node_xp); event_id, node_xp);
return -EINVAL; return -EINVAL;
} }
...@@ -1594,4 +1594,4 @@ module_init(arm_ccn_init); ...@@ -1594,4 +1594,4 @@ module_init(arm_ccn_init);
module_exit(arm_ccn_exit); module_exit(arm_ccn_exit);
MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
...@@ -339,7 +339,7 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) ...@@ -339,7 +339,7 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
return IRQ_NONE; return IRQ_NONE;
start_clock = sched_clock(); start_clock = sched_clock();
ret = armpmu->handle_irq(irq, armpmu); ret = armpmu->handle_irq(armpmu);
finish_clock = sched_clock(); finish_clock = sched_clock();
perf_sample_event_took(finish_clock - start_clock); perf_sample_event_took(finish_clock - start_clock);
......
...@@ -131,8 +131,7 @@ static ssize_t arm_spe_pmu_cap_show(struct device *dev, ...@@ -131,8 +131,7 @@ static ssize_t arm_spe_pmu_cap_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
struct arm_spe_pmu *spe_pmu = platform_get_drvdata(pdev);
struct dev_ext_attribute *ea = struct dev_ext_attribute *ea =
container_of(attr, struct dev_ext_attribute, attr); container_of(attr, struct dev_ext_attribute, attr);
int cap = (long)ea->var; int cap = (long)ea->var;
...@@ -247,8 +246,7 @@ static ssize_t arm_spe_pmu_get_attr_cpumask(struct device *dev, ...@@ -247,8 +246,7 @@ static ssize_t arm_spe_pmu_get_attr_cpumask(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
struct arm_spe_pmu *spe_pmu = platform_get_drvdata(pdev);
return cpumap_print_to_pagebuf(true, buf, &spe_pmu->supported_cpus); return cpumap_print_to_pagebuf(true, buf, &spe_pmu->supported_cpus);
} }
......
...@@ -78,7 +78,7 @@ struct arm_pmu { ...@@ -78,7 +78,7 @@ struct arm_pmu {
struct pmu pmu; struct pmu pmu;
cpumask_t supported_cpus; cpumask_t supported_cpus;
char *name; char *name;
irqreturn_t (*handle_irq)(int irq_num, void *dev); irqreturn_t (*handle_irq)(struct arm_pmu *pmu);
void (*enable)(struct perf_event *event); void (*enable)(struct perf_event *event);
void (*disable)(struct perf_event *event); void (*disable)(struct perf_event *event);
int (*get_event_idx)(struct pmu_hw_events *hw_events, int (*get_event_idx)(struct pmu_hw_events *hw_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