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
This commit is contained in:
Catalin Marinas 2018-05-31 18:09:38 +01:00
commit cb877710e5
11 changed files with 64 additions and 69 deletions

View File

@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irqflags.h>
@ -174,6 +175,7 @@ bool mcpm_is_available(void)
{
return (platform_ops) ? true : false;
}
EXPORT_SYMBOL_GPL(mcpm_is_available);
/*
* We can't use regular spinlocks. In the switcher case, it is possible

View File

@ -303,12 +303,10 @@ static void armv6pmu_enable_event(struct perf_event *event)
}
static irqreturn_t
armv6pmu_handle_irq(int irq_num,
void *dev)
armv6pmu_handle_irq(struct arm_pmu *cpu_pmu)
{
unsigned long pmcr = armv6_pmcr_read();
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 pt_regs *regs;
int idx;

View File

@ -946,11 +946,10 @@ static void armv7pmu_disable_event(struct perf_event *event)
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;
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 pt_regs *regs;
int idx;

View File

@ -142,11 +142,10 @@ xscale1_pmnc_counter_has_overflowed(unsigned long pmnc,
}
static irqreturn_t
xscale1pmu_handle_irq(int irq_num, void *dev)
xscale1pmu_handle_irq(struct arm_pmu *cpu_pmu)
{
unsigned long pmnc;
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 pt_regs *regs;
int idx;
@ -489,11 +488,10 @@ xscale2_pmnc_counter_has_overflowed(unsigned long of_flags,
}
static irqreturn_t
xscale2pmu_handle_irq(int irq_num, void *dev)
xscale2pmu_handle_irq(struct arm_pmu *cpu_pmu)
{
unsigned long pmnc, of_flags;
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 pt_regs *regs;
int idx;

View File

@ -670,11 +670,10 @@ static void armv8pmu_disable_event(struct perf_event *event)
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;
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 pt_regs *regs;
int idx;

View File

@ -6,30 +6,32 @@ menu "Performance monitor support"
depends on PERF_EVENTS
config ARM_CCI_PMU
bool
tristate "ARM CCI PMU driver"
depends on (ARM && CPU_V7) || ARM64
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
bool "ARM CCI400 PMU support"
depends on (ARM && CPU_V7) || ARM64
bool "support CCI-400"
default y
depends on ARM_CCI_PMU
select ARM_CCI400_COMMON
select ARM_CCI_PMU
help
Support for PMU events monitoring on the ARM CCI-400 (cache coherent
interconnect). CCI-400 supports counting events related to the
connected slave/master interfaces.
CCI-400 provides 4 independent event counters counting events related
to the connected slave/master interfaces, plus a cycle counter.
config ARM_CCI5xx_PMU
bool "ARM CCI-500/CCI-550 PMU support"
depends on (ARM && CPU_V7) || ARM64
select ARM_CCI_PMU
bool "support CCI-500/CCI-550"
default y
depends on ARM_CCI_PMU
help
Support for PMU events monitoring on the ARM CCI-500/CCI-550 cache
coherent interconnects. Both of them provide 8 independent event counters,
which can count events pertaining to the slave/master interfaces as well
as the internal events to the CCI.
If unsure, say Y
CCI-500/CCI-550 both provide 8 independent event counters, which can
count events pertaining to the slave/master interfaces as well as the
internal events to the CCI.
config ARM_CCN
tristate "ARM CCN driver support"
@ -94,7 +96,7 @@ config XGENE_PMU
config ARM_SPE_PMU
tristate "Enable support for the ARMv8.2 Statistical Profiling Extension"
depends on PERF_EVENTS && ARM64
depends on ARM64
help
Enable perf support for the ARMv8.2 Statistical Profiling
Extension, which provides periodic sampling of operations in

View File

@ -120,9 +120,9 @@ enum cci_models {
static void pmu_write_counters(struct cci_pmu *cci_pmu,
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);
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);
#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
@ -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 hw_perf_event *hwc = &event->hw;
int idx;
int err = 0;
perf_pmu_disable(event->pmu);
/* If we don't have a space for the counter then finish early. */
idx = pmu_get_event_idx(hw_events, event);
if (idx < 0) {
err = idx;
goto out;
}
if (idx < 0)
return idx;
event->hw.idx = idx;
hw_events->events[idx] = event;
@ -1205,9 +1200,7 @@ static int cci_pmu_add(struct perf_event *event, int flags)
/* Propagate our changes to the userspace mapping. */
perf_event_update_userpage(event);
out:
perf_pmu_enable(event->pmu);
return err;
return 0;
}
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)
*/
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 (validate_group(event) != 0)
return -EINVAL;
@ -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;
cci_pmu->pmu = (struct pmu) {
.module = THIS_MODULE,
.name = cci_pmu->model->name,
.task_ctx_nr = perf_invalid_context,
.pmu_enable = cci_pmu_enable,
@ -1466,7 +1451,7 @@ static int cci_pmu_offline_cpu(unsigned int cpu)
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
[CCI400_R0] = {
.name = "CCI_400",
@ -1588,6 +1573,7 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
#endif
{},
};
MODULE_DEVICE_TABLE(of, arm_cci_pmu_matches);
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)
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 = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = arm_cci_pmu_matches,
},
.probe = cci_pmu_probe,
.remove = cci_pmu_remove,
};
builtin_platform_driver(cci_pmu_driver);
MODULE_LICENSE("GPL");
module_platform_driver(cci_pmu_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ARM CCI PMU support");

View File

@ -736,7 +736,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
ccn = pmu_to_arm_ccn(event->pmu);
if (hw->sample_period) {
dev_warn(ccn->dev, "Sampling not supported!\n");
dev_dbg(ccn->dev, "Sampling not supported!\n");
return -EOPNOTSUPP;
}
@ -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_idle || event->attr.exclude_host ||
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;
}
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;
}
/*
@ -771,13 +771,13 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
switch (type) {
case CCN_TYPE_MN:
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;
}
break;
case CCN_TYPE_XP:
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;
}
break;
@ -785,11 +785,11 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
break;
default:
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;
}
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);
return -EINVAL;
}
@ -808,19 +808,19 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
if (event_id != e->event)
continue;
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);
return -EINVAL;
}
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);
return -EINVAL;
}
valid = 1;
}
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);
return -EINVAL;
}
@ -1594,4 +1594,4 @@ module_init(arm_ccn_init);
module_exit(arm_ccn_exit);
MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@ -339,7 +339,7 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
return IRQ_NONE;
start_clock = sched_clock();
ret = armpmu->handle_irq(irq, armpmu);
ret = armpmu->handle_irq(armpmu);
finish_clock = sched_clock();
perf_sample_event_took(finish_clock - start_clock);

View File

@ -131,8 +131,7 @@ static ssize_t arm_spe_pmu_cap_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct arm_spe_pmu *spe_pmu = platform_get_drvdata(pdev);
struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
struct dev_ext_attribute *ea =
container_of(attr, struct dev_ext_attribute, attr);
int cap = (long)ea->var;
@ -247,8 +246,7 @@ static ssize_t arm_spe_pmu_get_attr_cpumask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct arm_spe_pmu *spe_pmu = platform_get_drvdata(pdev);
struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
return cpumap_print_to_pagebuf(true, buf, &spe_pmu->supported_cpus);
}

View File

@ -78,7 +78,7 @@ struct arm_pmu {
struct pmu pmu;
cpumask_t supported_cpus;
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 (*disable)(struct perf_event *event);
int (*get_event_idx)(struct pmu_hw_events *hw_events,