Verified Commit fc4e1153 authored by Leonard Crestez's avatar Leonard Crestez Committed by Sebastian Krzyszkowiak

perf/core: Introduce perf_get_pmu_by_node API

Add a new public API to fetch a pointer to struct pmu from a devicetree
node devicetree node. This is meant to be used by other drivers to
create in-kernel counter for custom hardware PMUs with automatically
allocated pmu->type.

This is implementated by adding a new "parent_dev" field which pmu
drivers can optionally fill. This parent device is set as the parent of
the pmu->dev created on the pmu_bus. This also has the nice side-effect
of creating additional symlinks inside sysfs.

The actual per_get_pmu_by_node function is implemented through
bus_find_device and callers are asked to "put_device(pmu->dev)" when
done. This might cause problems if pmu_bus is initialize late but
consumers should handle errors by returning -EPROBE_DEFER anyway.
Signed-off-by: default avatarLeonard Crestez <leonard.crestez@nxp.com>
parent 7253d36e
......@@ -202,6 +202,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
return -ENOMEM;
pmu->plat_device = pdev;
pmu->pmu.parent_dev = &pdev->dev;
ret = pmu_parse_irqs(pmu);
if (ret)
......
......@@ -673,6 +673,7 @@ static int ddr_perf_probe(struct platform_device *pdev)
goto ddr_perf_err;
}
pmu->pmu.parent_dev = &pdev->dev;
ret = perf_pmu_register(&pmu->pmu, name, -1);
if (ret)
goto ddr_perf_err;
......
......@@ -271,6 +271,7 @@ struct pmu {
struct module *module;
struct device *dev;
struct device *parent_dev;
const struct attribute_group **attr_groups;
const struct attribute_group **attr_update;
const char *name;
......@@ -937,6 +938,14 @@ extern void perf_event_itrace_started(struct perf_event *event);
extern int perf_pmu_register(struct pmu *pmu, const char *name, int type);
extern void perf_pmu_unregister(struct pmu *pmu);
#ifdef CONFIG_OF
extern struct pmu* perf_get_pmu_by_node(struct device_node *node);
#else
static inline struct pmu* perf_get_pmu_by_node(struct device_node *node) {
return NULL;
}
#endif
extern int perf_num_counters(void);
extern const char *perf_pmu_name(void);
extern void __perf_event_task_sched_in(struct task_struct *prev,
......
......@@ -10667,6 +10667,7 @@ static int pmu_dev_alloc(struct pmu *pmu)
dev_set_drvdata(pmu->dev, pmu);
pmu->dev->bus = &pmu_bus;
pmu->dev->parent = pmu->parent_dev;
pmu->dev->release = pmu_dev_release;
ret = device_add(pmu->dev);
if (ret)
......@@ -10696,6 +10697,30 @@ static int pmu_dev_alloc(struct pmu *pmu)
goto out;
}
#ifdef CONFIG_OF
static int perf_match_parent_of_node(struct device *dev, const void *np)
{
return dev->parent && dev->parent->of_node == np;
}
/**
* perf_get_pmu_by_node() - Fetch PMU instance via devicetree node
*
* @node: devicetree node for PMU
*
* Caller should put_device(pmu-dev) when done.
*/
struct pmu* perf_get_pmu_by_node(struct device_node *node)
{
struct device* dev;
dev = bus_find_device(&pmu_bus, NULL, node, perf_match_parent_of_node);
return dev ? dev_get_drvdata(dev) : NULL;
}
EXPORT_SYMBOL_GPL(perf_get_pmu_by_node);
#endif
static struct lock_class_key cpuctx_mutex;
static struct lock_class_key cpuctx_lock;
......
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