qcom-llcc-pmu: Update the LLCC PMU configurations for kona
Kona has new LLCC PMU version. This brought in changes in the monitor enable, disable and configuration registers and hence made code changes accordingly to read cache misses for multiple CPUs. Change-Id: I4d25487966a31f12143e2f99264a25d8c38f0188 Signed-off-by: Rama Aparna Mallavarapu <aparnam@codeaurora.org> [avajid@codeaurora.org: updated version enum, fixed disable/clear masks and made minor styling changes] Signed-off-by: Amir Vajid <avajid@codeaurora.org>
This commit is contained in:
parent
e43263bdea
commit
b6d80a179b
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
@ -14,11 +15,17 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
enum llcc_pmu_version {
|
||||
LLCC_PMU_VER1 = 1,
|
||||
LLCC_PMU_VER2,
|
||||
};
|
||||
|
||||
struct llcc_pmu {
|
||||
struct pmu pmu;
|
||||
struct hlist_node node;
|
||||
void __iomem *lagg_base;
|
||||
struct perf_event event;
|
||||
enum llcc_pmu_version ver;
|
||||
};
|
||||
|
||||
#define MON_CFG(m) ((m)->lagg_base + 0x200)
|
||||
@ -26,9 +33,10 @@ struct llcc_pmu {
|
||||
#define to_llcc_pmu(ptr) (container_of(ptr, struct llcc_pmu, pmu))
|
||||
|
||||
#define LLCC_RD_EV 0x1000
|
||||
#define ENABLE 0x01
|
||||
#define ENABLE 0x1
|
||||
#define CLEAR 0x10
|
||||
#define DISABLE 0x00
|
||||
#define CLEAR_POS 16
|
||||
#define DISABLE 0x0
|
||||
#define SCALING_FACTOR 0x3
|
||||
#define NUM_COUNTERS NR_CPUS
|
||||
#define VALUE_MASK 0xFFFFFF
|
||||
@ -38,6 +46,93 @@ static unsigned int users;
|
||||
static raw_spinlock_t counter_lock;
|
||||
static raw_spinlock_t users_lock;
|
||||
static ktime_t last_read;
|
||||
static DEFINE_PER_CPU(unsigned int, users_alive);
|
||||
|
||||
static void mon_disable(struct llcc_pmu *llccpmu, int cpu)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (!llccpmu->ver) {
|
||||
pr_err("LLCCPMU version not correct\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (llccpmu->ver) {
|
||||
case LLCC_PMU_VER1:
|
||||
writel_relaxed(DISABLE, MON_CFG(llccpmu));
|
||||
break;
|
||||
case LLCC_PMU_VER2:
|
||||
reg = readl_relaxed(MON_CFG(llccpmu));
|
||||
reg &= ~(ENABLE << cpu);
|
||||
writel_relaxed(reg, MON_CFG(llccpmu));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mon_clear(struct llcc_pmu *llccpmu, int cpu)
|
||||
{
|
||||
int clear_bit = CLEAR_POS + cpu;
|
||||
u32 reg;
|
||||
|
||||
if (!llccpmu->ver) {
|
||||
pr_err("LLCCPMU version not correct\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (llccpmu->ver) {
|
||||
case LLCC_PMU_VER1:
|
||||
writel_relaxed(CLEAR, MON_CFG(llccpmu));
|
||||
break;
|
||||
case LLCC_PMU_VER2:
|
||||
reg = readl_relaxed(MON_CFG(llccpmu));
|
||||
reg |= (ENABLE << clear_bit);
|
||||
writel_relaxed(reg, MON_CFG(llccpmu));
|
||||
reg &= ~(ENABLE << clear_bit);
|
||||
writel_relaxed(reg, MON_CFG(llccpmu));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mon_enable(struct llcc_pmu *llccpmu, int cpu)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (!llccpmu->ver) {
|
||||
pr_err("LLCCPMU version not correct\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (llccpmu->ver) {
|
||||
case LLCC_PMU_VER1:
|
||||
writel_relaxed(ENABLE, MON_CFG(llccpmu));
|
||||
break;
|
||||
case LLCC_PMU_VER2:
|
||||
reg = readl_relaxed(MON_CFG(llccpmu));
|
||||
reg |= (ENABLE << cpu);
|
||||
writel_relaxed(reg, MON_CFG(llccpmu));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long read_cnt(struct llcc_pmu *llccpmu, int cpu)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
if (!llccpmu->ver) {
|
||||
pr_err("LLCCPMU version not correct\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (llccpmu->ver) {
|
||||
case LLCC_PMU_VER1:
|
||||
value = readl_relaxed(MON_CNT(llccpmu, cpu));
|
||||
break;
|
||||
case LLCC_PMU_VER2:
|
||||
value = readl_relaxed(MON_CNT(llccpmu, cpu));
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int qcom_llcc_event_init(struct perf_event *event)
|
||||
{
|
||||
@ -58,17 +153,26 @@ static void qcom_llcc_event_read(struct perf_event *event)
|
||||
ktime_t cur;
|
||||
|
||||
raw_spin_lock_irqsave(&counter_lock, irq_flags);
|
||||
cur = ktime_get();
|
||||
if (ktime_ms_delta(cur, last_read) > 1) {
|
||||
writel_relaxed(DISABLE, MON_CFG(llccpmu));
|
||||
for (i = 0; i < NUM_COUNTERS; i++) {
|
||||
raw = readl_relaxed(MON_CNT(llccpmu, i));
|
||||
raw &= VALUE_MASK;
|
||||
llcc_stats[i] += (u64) raw << SCALING_FACTOR;
|
||||
if (llccpmu->ver == LLCC_PMU_VER1) {
|
||||
cur = ktime_get();
|
||||
if (ktime_ms_delta(cur, last_read) > 1) {
|
||||
mon_disable(llccpmu, cpu);
|
||||
for (i = 0; i < NUM_COUNTERS; i++) {
|
||||
raw = read_cnt(llccpmu, i);
|
||||
raw &= VALUE_MASK;
|
||||
llcc_stats[i] += (u64) raw << SCALING_FACTOR;
|
||||
}
|
||||
last_read = cur;
|
||||
mon_clear(llccpmu, cpu);
|
||||
mon_enable(llccpmu, cpu);
|
||||
}
|
||||
last_read = cur;
|
||||
writel_relaxed(CLEAR, MON_CFG(llccpmu));
|
||||
writel_relaxed(ENABLE, MON_CFG(llccpmu));
|
||||
} else {
|
||||
mon_disable(llccpmu, cpu);
|
||||
raw = read_cnt(llccpmu, cpu);
|
||||
raw &= VALUE_MASK;
|
||||
llcc_stats[cpu] += (u64) raw << SCALING_FACTOR;
|
||||
mon_clear(llccpmu, cpu);
|
||||
mon_enable(llccpmu, cpu);
|
||||
}
|
||||
|
||||
if (!(event->hw.state & PERF_HES_STOPPED))
|
||||
@ -92,11 +196,22 @@ static void qcom_llcc_event_stop(struct perf_event *event, int flags)
|
||||
static int qcom_llcc_event_add(struct perf_event *event, int flags)
|
||||
{
|
||||
struct llcc_pmu *llccpmu = to_llcc_pmu(event->pmu);
|
||||
unsigned int cpu_users;
|
||||
|
||||
raw_spin_lock(&users_lock);
|
||||
if (!users)
|
||||
writel_relaxed(ENABLE, MON_CFG(llccpmu));
|
||||
users++;
|
||||
|
||||
if (llccpmu->ver == LLCC_PMU_VER1) {
|
||||
if (!users)
|
||||
mon_enable(llccpmu, event->cpu);
|
||||
users++;
|
||||
} else {
|
||||
cpu_users = per_cpu(users_alive, event->cpu);
|
||||
if (!cpu_users)
|
||||
mon_enable(llccpmu, event->cpu);
|
||||
cpu_users++;
|
||||
per_cpu(users_alive, event->cpu) = cpu_users;
|
||||
}
|
||||
|
||||
raw_spin_unlock(&users_lock);
|
||||
|
||||
event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
|
||||
@ -110,11 +225,22 @@ static int qcom_llcc_event_add(struct perf_event *event, int flags)
|
||||
static void qcom_llcc_event_del(struct perf_event *event, int flags)
|
||||
{
|
||||
struct llcc_pmu *llccpmu = to_llcc_pmu(event->pmu);
|
||||
unsigned int cpu_users;
|
||||
|
||||
raw_spin_lock(&users_lock);
|
||||
users--;
|
||||
if (!users)
|
||||
writel_relaxed(DISABLE, MON_CFG(llccpmu));
|
||||
|
||||
if (llccpmu->ver == LLCC_PMU_VER1) {
|
||||
users--;
|
||||
if (!users)
|
||||
mon_disable(llccpmu, event->cpu);
|
||||
} else {
|
||||
cpu_users = per_cpu(users_alive, event->cpu);
|
||||
cpu_users--;
|
||||
if (!cpu_users)
|
||||
mon_disable(llccpmu, event->cpu);
|
||||
per_cpu(users_alive, event->cpu) = cpu_users;
|
||||
}
|
||||
|
||||
raw_spin_unlock(&users_lock);
|
||||
}
|
||||
|
||||
@ -128,6 +254,13 @@ static int qcom_llcc_pmu_probe(struct platform_device *pdev)
|
||||
if (!llccpmu)
|
||||
return -ENOMEM;
|
||||
|
||||
llccpmu->ver = (enum llcc_pmu_version)
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
if (!llccpmu->ver) {
|
||||
pr_err("Unknown device type!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
llccpmu->pmu = (struct pmu) {
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
|
||||
@ -161,7 +294,8 @@ static int qcom_llcc_pmu_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_llcc_pmu_match_table[] = {
|
||||
{ .compatible = "qcom,qcom-llcc-pmu" },
|
||||
{ .compatible = "qcom,llcc-pmu-ver1", .data = (void *) LLCC_PMU_VER1 },
|
||||
{ .compatible = "qcom,llcc-pmu-ver2", .data = (void *) LLCC_PMU_VER2 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user