From 559bd233f1ca5f4a00d7c809acac8e1691f15ef2 Mon Sep 17 00:00:00 2001 From: Avinash Philip Date: Fri, 12 Apr 2019 14:30:47 +0530 Subject: [PATCH 1/2] drivers: llcc_perfmon: support for dual memory controller added llcc supports 2 memory controllers in backend on certain systems. This patch adds support for dual memory controllers. Also fixed filter related changes in LLCC. Cleaned up the code for better code walk. Change-Id: Ie054d9182b20ec0811f117c2289aa857f0384baf Signed-off-by: Avinash Philip --- drivers/soc/qcom/llcc_events.h | 1 + drivers/soc/qcom/llcc_perfmon.c | 328 +++++++++++++++++++------------- drivers/soc/qcom/llcc_perfmon.h | 33 ++-- 3 files changed, 218 insertions(+), 144 deletions(-) diff --git a/drivers/soc/qcom/llcc_events.h b/drivers/soc/qcom/llcc_events.h index 1c37cd04e42a..1359ad65f5ae 100644 --- a/drivers/soc/qcom/llcc_events.h +++ b/drivers/soc/qcom/llcc_events.h @@ -15,6 +15,7 @@ enum event_port_select { EVENT_PORT_TRP, EVENT_PORT_DRP, EVENT_PORT_PMGR, + EVENT_PORT_BEAC1, EVENT_PORT_TENURE, EVENT_PORT_TLAT, }; diff --git a/drivers/soc/qcom/llcc_perfmon.c b/drivers/soc/qcom/llcc_perfmon.c index 2e68bba5e94a..6bae29d6e815 100644 --- a/drivers/soc/qcom/llcc_perfmon.c +++ b/drivers/soc/qcom/llcc_perfmon.c @@ -19,7 +19,7 @@ #include "llcc_perfmon.h" #define LLCC_PERFMON_NAME "qcom_llcc_perfmon" -#define LLCC_PERFMON_COUNTER_MAX 16 +#define MAX_CNTR 16 #define MAX_NUMBER_OF_PORTS 8 #define NUM_CHANNELS 16 #define DELIM_CHAR " " @@ -45,7 +45,7 @@ struct llcc_perfmon_private; */ struct event_port_ops { void (*event_config)(struct llcc_perfmon_private *priv, - unsigned int type, unsigned int num, bool enable); + unsigned int type, unsigned int *num, bool enable); void (*event_enable)(struct llcc_perfmon_private *priv, bool enable); void (*event_filter_config)(struct llcc_perfmon_private *priv, enum filter_type filter, unsigned long match, @@ -55,12 +55,12 @@ struct event_port_ops { /** * struct llcc_perfmon_private - llcc perfmon private * @llcc_map: llcc register address space map + * @llcc_bcast_map: llcc broadcast register address space map * @bank_off: Offset of llcc banks * @num_banks: Number of banks supported * @port_ops: struct event_port_ops * @configured: Mapping of configured event counters - * @configured_counters: - * Count of configured counters. + * @configured_cntrs: Count of configured counters. * @enables_port: Port enabled for perfmon configuration * @filtered_ports: Port filter enabled * @port_configd: Number of perfmon port configuration supported @@ -76,8 +76,8 @@ struct llcc_perfmon_private { unsigned int bank_off[NUM_CHANNELS]; unsigned int num_banks; struct event_port_ops *port_ops[MAX_NUMBER_OF_PORTS]; - struct llcc_perfmon_counter_map configured[LLCC_PERFMON_COUNTER_MAX]; - unsigned int configured_counters; + struct llcc_perfmon_counter_map configured[MAX_CNTR]; + unsigned int configured_cntrs; unsigned int enables_port; unsigned int filtered_ports; unsigned int port_configd; @@ -113,18 +113,20 @@ static void llcc_bcast_modify(struct llcc_perfmon_private *llcc_priv, static void perfmon_counter_dump(struct llcc_perfmon_private *llcc_priv) { + struct llcc_perfmon_counter_map *counter_map; uint32_t val; unsigned int i, j; - if (!llcc_priv->configured_counters) + if (!llcc_priv->configured_cntrs) return; llcc_bcast_write(llcc_priv, PERFMON_DUMP, MONITOR_DUMP); - for (i = 0; i < llcc_priv->configured_counters; i++) { + for (i = 0; i < llcc_priv->configured_cntrs; i++) { + counter_map = &llcc_priv->configured[i]; for (j = 0; j < llcc_priv->num_banks; j++) { regmap_read(llcc_priv->llcc_map, llcc_priv->bank_off[j] + LLCC_COUNTER_n_VALUE(i), &val); - llcc_priv->configured[i].counter_dump[j] += val; + counter_map->counter_dump[j] += val; } } } @@ -133,26 +135,39 @@ static ssize_t perfmon_counter_dump_show(struct device *dev, struct device_attribute *attr, char *buf) { struct llcc_perfmon_private *llcc_priv = dev_get_drvdata(dev); + struct llcc_perfmon_counter_map *counter_map; unsigned int i, j; unsigned long long total; ssize_t cnt = 0; - if (llcc_priv->configured_counters == 0) { + if (llcc_priv->configured_cntrs == 0) { pr_err("counters not configured\n"); return cnt; } perfmon_counter_dump(llcc_priv); - for (i = 0; i < llcc_priv->configured_counters - 1; i++) { - cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "Port %02d,", - llcc_priv->configured[i].port_sel); - cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "Event %02d,", - llcc_priv->configured[i].event_sel); - + for (i = 0; i < llcc_priv->configured_cntrs - 1; i++) { total = 0; - for (j = 0; j < llcc_priv->num_banks; j++) { - total += llcc_priv->configured[i].counter_dump[j]; - llcc_priv->configured[i].counter_dump[j] = 0; + counter_map = &llcc_priv->configured[i]; + cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, + "Port %02d,Event %02d,", + counter_map->port_sel, counter_map->event_sel); + + if ((counter_map->port_sel == EVENT_PORT_BEAC) && + (llcc_priv->num_mc > 1)) { + /* DBX uses 2 counters for BEAC 0 & 1 */ + i++; + for (j = 0; j < llcc_priv->num_banks; j++) { + total += counter_map->counter_dump[j]; + counter_map->counter_dump[j] = 0; + total += counter_map[1].counter_dump[j]; + counter_map[1].counter_dump[j] = 0; + } + } else { + for (j = 0; j < llcc_priv->num_banks; j++) { + total += counter_map->counter_dump[j]; + counter_map->counter_dump[j] = 0; + } } cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "0x%016llx\n", @@ -161,9 +176,10 @@ static ssize_t perfmon_counter_dump_show(struct device *dev, cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "CYCLE COUNT, ,"); total = 0; + counter_map = &llcc_priv->configured[i]; for (j = 0; j < llcc_priv->num_banks; j++) { - total += llcc_priv->configured[i].counter_dump[j]; - llcc_priv->configured[i].counter_dump[j] = 0; + total += counter_map->counter_dump[j]; + counter_map->counter_dump[j] = 0; } cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "0x%016llx\n", total); @@ -179,19 +195,19 @@ static ssize_t perfmon_configure_store(struct device *dev, { struct llcc_perfmon_private *llcc_priv = dev_get_drvdata(dev); struct event_port_ops *port_ops; - unsigned int j = 0, k; + struct llcc_perfmon_counter_map *counter_map; + unsigned int j = 0, k, end_cntrs; unsigned long port_sel, event_sel; uint32_t val; char *token, *delim = DELIM_CHAR; mutex_lock(&llcc_priv->mutex); - if (llcc_priv->configured_counters) { + if (llcc_priv->configured_cntrs) { pr_err("Counters configured already, remove & try again\n"); mutex_unlock(&llcc_priv->mutex); return -EINVAL; } - llcc_priv->configured_counters = 0; token = strsep((char **)&buf, delim); while (token != NULL) { @@ -214,32 +230,35 @@ static ssize_t perfmon_configure_store(struct device *dev, continue; } - llcc_priv->configured[j].port_sel = port_sel; - llcc_priv->configured[j].event_sel = event_sel; + /* Last perfmon counter for cycle counter */ + end_cntrs = 1; + if (port_sel == EVENT_PORT_BEAC) + end_cntrs = llcc_priv->num_mc; + + if (j == (MAX_CNTR - end_cntrs)) + break; + + counter_map = &llcc_priv->configured[j]; + counter_map->port_sel = port_sel; + counter_map->event_sel = event_sel; for (k = 0; k < llcc_priv->num_banks; k++) - llcc_priv->configured[j].counter_dump[k] = 0; + counter_map->counter_dump[k] = 0; port_ops = llcc_priv->port_ops[port_sel]; - pr_info("counter %d configured for event %ld from port %ld\n", - j, event_sel, port_sel); - port_ops->event_config(llcc_priv, event_sel, j++, true); - if (!(llcc_priv->enables_port & (1 << port_sel))) - if (port_ops->event_enable) - port_ops->event_enable(llcc_priv, true); + port_ops->event_config(llcc_priv, event_sel, &j, true); + pr_info("counter %2d configured for event %2ld from port %ld\n", + j++, event_sel, port_sel); + if (((llcc_priv->enables_port & (1 << port_sel)) == 0) && + (port_ops->event_enable)) + port_ops->event_enable(llcc_priv, true); llcc_priv->enables_port |= (1 << port_sel); - - /* Last perfmon counter for cycle counter */ - if (llcc_priv->configured_counters++ == - (LLCC_PERFMON_COUNTER_MAX - 2)) - break; } /* configure clock event */ val = COUNT_CLOCK_EVENT | CLEAR_ON_ENABLE | CLEAR_ON_DUMP; - llcc_bcast_write(llcc_priv, PERFMON_COUNTER_n_CONFIG(j), val); - - llcc_priv->configured_counters++; + llcc_bcast_write(llcc_priv, PERFMON_COUNTER_n_CONFIG(j++), val); + llcc_priv->configured_cntrs = j; mutex_unlock(&llcc_priv->mutex); return count; } @@ -249,12 +268,13 @@ static ssize_t perfmon_remove_store(struct device *dev, { struct llcc_perfmon_private *llcc_priv = dev_get_drvdata(dev); struct event_port_ops *port_ops; - unsigned int j = 0, counter_remove = 0; + struct llcc_perfmon_counter_map *counter_map; + unsigned int j = 0, end_cntrs; unsigned long port_sel, event_sel; char *token, *delim = DELIM_CHAR; mutex_lock(&llcc_priv->mutex); - if (!llcc_priv->configured_counters) { + if (!llcc_priv->configured_cntrs) { pr_err("Counters not configured\n"); mutex_unlock(&llcc_priv->mutex); return -EINVAL; @@ -282,29 +302,32 @@ static ssize_t perfmon_remove_store(struct device *dev, continue; } - /* put dummy values */ - llcc_priv->configured[j].port_sel = MAX_NUMBER_OF_PORTS; - llcc_priv->configured[j].event_sel = 100; - port_ops = llcc_priv->port_ops[port_sel]; - pr_info("removed counter %d for event %ld from port %ld\n", - j, event_sel, port_sel); + /* Last perfmon counter for cycle counter */ + end_cntrs = 1; + if (port_sel == EVENT_PORT_BEAC) + end_cntrs = llcc_priv->num_mc; - port_ops->event_config(llcc_priv, event_sel, j++, false); - if (llcc_priv->enables_port & (1 << port_sel)) - if (port_ops->event_enable) - port_ops->event_enable(llcc_priv, false); + if (j == (llcc_priv->configured_cntrs - end_cntrs)) + break; + + /* put dummy values */ + counter_map = &llcc_priv->configured[j]; + counter_map->port_sel = MAX_NUMBER_OF_PORTS; + counter_map->event_sel = 0; + port_ops = llcc_priv->port_ops[port_sel]; + port_ops->event_config(llcc_priv, event_sel, &j, false); + pr_info("removed counter %2d for event %2ld from port %2ld\n", + j++, event_sel, port_sel); + if ((llcc_priv->enables_port & (1 << port_sel)) && + (port_ops->event_enable)) + port_ops->event_enable(llcc_priv, false); llcc_priv->enables_port &= ~(1 << port_sel); - - /* Last perfmon counter for cycle counter */ - if (counter_remove++ == (LLCC_PERFMON_COUNTER_MAX - 2)) - break; } /* remove clock event */ llcc_bcast_write(llcc_priv, PERFMON_COUNTER_n_CONFIG(j), 0); - - llcc_priv->configured_counters = 0; + llcc_priv->configured_cntrs = 0; mutex_unlock(&llcc_priv->mutex); return count; } @@ -339,13 +362,12 @@ static ssize_t perfmon_filter_config_store(struct device *dev, char *token, *delim = DELIM_CHAR; enum filter_type filter = UNKNOWN; - if (llcc_priv->configured_counters) { + if (llcc_priv->configured_cntrs) { pr_err("remove configured events and try\n"); return count; } mutex_lock(&llcc_priv->mutex); - token = strsep((char **)&buf, delim); if (token != NULL) filter = find_filter_type(token); @@ -484,7 +506,7 @@ static ssize_t perfmon_start_store(struct device *dev, mutex_lock(&llcc_priv->mutex); if (start) { - if (!llcc_priv->configured_counters) { + if (!llcc_priv->configured_cntrs) { pr_err("start failed. perfmon not configured\n"); mutex_unlock(&llcc_priv->mutex); return -EINVAL; @@ -505,14 +527,13 @@ static ssize_t perfmon_start_store(struct device *dev, if (llcc_priv->expires) hrtimer_cancel(&llcc_priv->hrtimer); - if (!llcc_priv->configured_counters) + if (!llcc_priv->configured_cntrs) pr_err("stop failed. perfmon not configured\n"); } mask_val = PERFMON_MODE_MONITOR_MODE_MASK | PERFMON_MODE_MONITOR_EN_MASK; llcc_bcast_modify(llcc_priv, PERFMON_MODE, val, mask_val); - mutex_unlock(&llcc_priv->mutex); return count; } @@ -555,7 +576,6 @@ static ssize_t perfmon_scid_status_show(struct device *dev, for (i = 0; i < SCID_MAX; i++) { total = 0; offset = TRP_SCID_n_STATUS(i); - for (j = 0; j < llcc_priv->num_banks; j++) { regmap_read(llcc_priv->llcc_map, llcc_priv->bank_off[j] + offset, &val); @@ -604,39 +624,49 @@ static struct attribute_group llcc_perfmon_group = { .attrs = llcc_perfmon_attrs, }; -static void perfmon_counter_config(struct llcc_perfmon_private *llcc_priv, - unsigned int port, unsigned int event_counter_num) +static void perfmon_cntr_config(struct llcc_perfmon_private *llcc_priv, + unsigned int port, unsigned int counter_num, bool enable) { - uint32_t val; + uint32_t val = 0; - val = (port & PERFMON_PORT_SELECT_MASK) | - ((event_counter_num << EVENT_SELECT_SHIFT) & - PERFMON_EVENT_SELECT_MASK) | CLEAR_ON_ENABLE | CLEAR_ON_DUMP; - llcc_bcast_write(llcc_priv, PERFMON_COUNTER_n_CONFIG(event_counter_num), - val); + if (counter_num >= MAX_CNTR) + return; + + if (enable) + val = (port & PERFMON_PORT_SELECT_MASK) | + ((counter_num << EVENT_SELECT_SHIFT) & + PERFMON_EVENT_SELECT_MASK) | CLEAR_ON_ENABLE | + CLEAR_ON_DUMP; + + llcc_bcast_write(llcc_priv, PERFMON_COUNTER_n_CONFIG(counter_num), val); } static void feac_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; mask_val = EVENT_SEL_MASK; + if (llcc_priv->version == REV_2) + mask_val = EVENT_SEL_MASK7; + if (llcc_priv->filtered_ports & (1 << EVENT_PORT_FEAC)) mask_val |= FILTER_SEL_MASK | FILTER_EN_MASK; if (enable) { val = (event_type << EVENT_SEL_SHIFT) & EVENT_SEL_MASK; + if (llcc_priv->version == REV_2) + val = (event_type << EVENT_SEL_SHIFT) & + EVENT_SEL_MASK7; + if (llcc_priv->filtered_ports & (1 << EVENT_PORT_FEAC)) val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; - - counter_num = event_counter_num; } - llcc_bcast_modify(llcc_priv, FEAC_PROF_EVENT_n_CFG(event_counter_num), + llcc_bcast_modify(llcc_priv, FEAC_PROF_EVENT_n_CFG(*counter_num), val, mask_val); - perfmon_counter_config(llcc_priv, EVENT_PORT_FEAC, counter_num); + perfmon_cntr_config(llcc_priv, EVENT_PORT_FEAC, *counter_num, enable); } static void feac_event_enable(struct llcc_perfmon_private *llcc_priv, @@ -748,10 +778,10 @@ static struct event_port_ops feac_port_ops = { }; static void ferc_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; mask_val = EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_FERC)) @@ -762,12 +792,11 @@ static void ferc_event_config(struct llcc_perfmon_private *llcc_priv, if (llcc_priv->filtered_ports & (1 << EVENT_PORT_FERC)) val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; - counter_num = event_counter_num; } - llcc_bcast_modify(llcc_priv, FERC_PROF_EVENT_n_CFG(event_counter_num), + llcc_bcast_modify(llcc_priv, FERC_PROF_EVENT_n_CFG(*counter_num), val, mask_val); - perfmon_counter_config(llcc_priv, EVENT_PORT_FERC, counter_num); + perfmon_cntr_config(llcc_priv, EVENT_PORT_FERC, *counter_num, enable); } static void ferc_event_enable(struct llcc_perfmon_private *llcc_priv, @@ -810,10 +839,10 @@ static struct event_port_ops ferc_port_ops = { }; static void fewc_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; mask_val = EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_FEWC)) @@ -824,12 +853,11 @@ static void fewc_event_config(struct llcc_perfmon_private *llcc_priv, if (llcc_priv->filtered_ports & (1 << EVENT_PORT_FEWC)) val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; - counter_num = event_counter_num; } - llcc_bcast_modify(llcc_priv, FEWC_PROF_EVENT_n_CFG(event_counter_num), + llcc_bcast_modify(llcc_priv, FEWC_PROF_EVENT_n_CFG(*counter_num), val, mask_val); - perfmon_counter_config(llcc_priv, EVENT_PORT_FEWC, counter_num); + perfmon_cntr_config(llcc_priv, EVENT_PORT_FEWC, *counter_num, enable); } static void fewc_event_filter_config(struct llcc_perfmon_private *llcc_priv, @@ -857,17 +885,18 @@ static struct event_port_ops fewc_port_ops = { }; static void beac_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; uint32_t valcfg = 0, mask_valcfg; unsigned int mc_cnt, offset; + struct llcc_perfmon_counter_map *counter_map; mask_val = EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_BEAC)) { mask_val |= FILTER_SEL_MASK | FILTER_EN_MASK; - if (llcc_priv->version == REV_0) + if (llcc_priv->version == REV_2) mask_valcfg = BEAC_WR_BEAT_FILTER_SEL_MASK | BEAC_WR_BEAT_FILTER_EN_MASK | BEAC_RD_BEAT_FILTER_SEL_MASK | @@ -877,9 +906,8 @@ static void beac_event_config(struct llcc_perfmon_private *llcc_priv, if (enable) { val = (event_type << EVENT_SEL_SHIFT) & EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_BEAC)) { - val |= (FILTER_0 << FILTER_SEL_SHIFT) | - FILTER_EN; - if (llcc_priv->version == REV_0) + val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; + if (llcc_priv->version == REV_2) valcfg = (FILTER_0 << BEAC_WR_BEAT_FILTER_SEL_SHIFT) | BEAC_WR_BEAT_FILTER_EN | @@ -887,20 +915,35 @@ static void beac_event_config(struct llcc_perfmon_private *llcc_priv, BEAC_RD_BEAT_FILTER_SEL_SHIFT) | BEAC_RD_BEAT_FILTER_EN; } - - counter_num = event_counter_num; } for (mc_cnt = 0; mc_cnt < llcc_priv->num_mc; mc_cnt++) { - offset = BEAC_PROF_EVENT_n_CFG(event_counter_num) + + offset = BEAC_PROF_EVENT_n_CFG(*counter_num + mc_cnt) + mc_cnt * BEAC_INST_OFF; llcc_bcast_modify(llcc_priv, offset, val, mask_val); offset = BEAC_PROF_CFG + mc_cnt * BEAC_INST_OFF; llcc_bcast_modify(llcc_priv, offset, valcfg, mask_valcfg); + + perfmon_cntr_config(llcc_priv, EVENT_PORT_BEAC, *counter_num, + enable); + /* DBX uses 2 counters for BEAC 0 & 1 */ + if (mc_cnt == 1) + perfmon_cntr_config(llcc_priv, EVENT_PORT_BEAC1, + *counter_num + mc_cnt, enable); } - perfmon_counter_config(llcc_priv, EVENT_PORT_BEAC, counter_num); + /* DBX uses 2 counters for BEAC 0 & 1 */ + if (llcc_priv->num_mc > 1) { + counter_map = &llcc_priv->configured[(*counter_num)++]; + if (enable) { + counter_map->port_sel = EVENT_PORT_BEAC; + counter_map->event_sel = event_type; + } else { + counter_map->port_sel = MAX_NUMBER_OF_PORTS; + counter_map->event_sel = 100; + } + } } static void beac_event_enable(struct llcc_perfmon_private *llcc_priv, @@ -961,10 +1004,10 @@ static struct event_port_ops beac_port_ops = { }; static void berc_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; mask_val = EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_BERC)) @@ -974,13 +1017,11 @@ static void berc_event_config(struct llcc_perfmon_private *llcc_priv, val = (event_type << EVENT_SEL_SHIFT) & EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_BERC)) val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; - - counter_num = event_counter_num; } - llcc_bcast_modify(llcc_priv, BERC_PROF_EVENT_n_CFG(event_counter_num), + llcc_bcast_modify(llcc_priv, BERC_PROF_EVENT_n_CFG(*counter_num), val, mask_val); - perfmon_counter_config(llcc_priv, EVENT_PORT_BERC, counter_num); + perfmon_cntr_config(llcc_priv, EVENT_PORT_BERC, *counter_num, enable); } static void berc_event_enable(struct llcc_perfmon_private *llcc_priv, @@ -1023,26 +1064,31 @@ static struct event_port_ops berc_port_ops = { }; static void trp_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; mask_val = EVENT_SEL_MASK; + if (llcc_priv->version == REV_2) + mask_val = EVENT_SEL_MASK7; + if (llcc_priv->filtered_ports & (1 << EVENT_PORT_TRP)) mask_val |= FILTER_SEL_MASK | FILTER_EN_MASK; if (enable) { val = (event_type << EVENT_SEL_SHIFT) & EVENT_SEL_MASK; + if (llcc_priv->version == REV_2) + val = (event_type << EVENT_SEL_SHIFT) & + EVENT_SEL_MASK7; + if (llcc_priv->filtered_ports & (1 << EVENT_PORT_TRP)) val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; - - counter_num = event_counter_num; } - llcc_bcast_modify(llcc_priv, TRP_PROF_EVENT_n_CFG(event_counter_num), + llcc_bcast_modify(llcc_priv, TRP_PROF_EVENT_n_CFG(*counter_num), val, mask_val); - perfmon_counter_config(llcc_priv, EVENT_PORT_TRP, counter_num); + perfmon_cntr_config(llcc_priv, EVENT_PORT_TRP, *counter_num, enable); } static void trp_event_filter_config(struct llcc_perfmon_private *llcc_priv, @@ -1052,11 +1098,18 @@ static void trp_event_filter_config(struct llcc_perfmon_private *llcc_priv, uint32_t val = 0, mask_val; if (filter == SCID) { - if (enable) - val = (match << TRP_SCID_MATCH_SHIFT) | - (mask << TRP_SCID_MASK_SHIFT); + if (llcc_priv->version == REV_2) { + if (enable) + val = (1 << match); - mask_val = TRP_SCID_MATCH_MASK | TRP_SCID_MASK_MASK; + mask_val = SCID_MULTI_MATCH_MASK; + } else { + if (enable) + val = (match << TRP_SCID_MATCH_SHIFT) | + (mask << TRP_SCID_MASK_SHIFT); + + mask_val = TRP_SCID_MATCH_MASK | TRP_SCID_MASK_MASK; + } } else if (filter == WAY_ID) { if (enable) val = (match << TRP_WAY_ID_MATCH_SHIFT) | @@ -1074,7 +1127,12 @@ static void trp_event_filter_config(struct llcc_perfmon_private *llcc_priv, return; } - llcc_bcast_modify(llcc_priv, TRP_PROF_FILTER_0_CFG1, val, mask_val); + if ((llcc_priv->version == REV_2) && (filter == SCID)) + llcc_bcast_modify(llcc_priv, TRP_PROF_FILTER_0_CFG2, val, + mask_val); + else + llcc_bcast_modify(llcc_priv, TRP_PROF_FILTER_0_CFG1, val, + mask_val); } static struct event_port_ops trp_port_ops = { @@ -1083,26 +1141,31 @@ static struct event_port_ops trp_port_ops = { }; static void drp_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; mask_val = EVENT_SEL_MASK; + if (llcc_priv->version == REV_2) + mask_val = EVENT_SEL_MASK7; + if (llcc_priv->filtered_ports & (1 << EVENT_PORT_DRP)) mask_val |= FILTER_SEL_MASK | FILTER_EN_MASK; if (enable) { val = (event_type << EVENT_SEL_SHIFT) & EVENT_SEL_MASK; + if (llcc_priv->version == REV_2) + val = (event_type << EVENT_SEL_SHIFT) & + EVENT_SEL_MASK7; + if (llcc_priv->filtered_ports & (1 << EVENT_PORT_DRP)) val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; - - counter_num = event_counter_num; } - llcc_bcast_modify(llcc_priv, DRP_PROF_EVENT_n_CFG(event_counter_num), + llcc_bcast_modify(llcc_priv, DRP_PROF_EVENT_n_CFG(*counter_num), val, mask_val); - perfmon_counter_config(llcc_priv, EVENT_PORT_DRP, counter_num); + perfmon_cntr_config(llcc_priv, EVENT_PORT_DRP, *counter_num, enable); } static void drp_event_enable(struct llcc_perfmon_private *llcc_priv, @@ -1123,10 +1186,10 @@ static struct event_port_ops drp_port_ops = { }; static void pmgr_event_config(struct llcc_perfmon_private *llcc_priv, - unsigned int event_type, unsigned int event_counter_num, + unsigned int event_type, unsigned int *counter_num, bool enable) { - uint32_t val = 0, mask_val, counter_num = 0; + uint32_t val = 0, mask_val; mask_val = EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_PMGR)) @@ -1136,13 +1199,11 @@ static void pmgr_event_config(struct llcc_perfmon_private *llcc_priv, val = (event_type << EVENT_SEL_SHIFT) & EVENT_SEL_MASK; if (llcc_priv->filtered_ports & (1 << EVENT_PORT_PMGR)) val |= (FILTER_0 << FILTER_SEL_SHIFT) | FILTER_EN; - - counter_num = event_counter_num; } - llcc_bcast_modify(llcc_priv, PMGR_PROF_EVENT_n_CFG(event_counter_num), + llcc_bcast_modify(llcc_priv, PMGR_PROF_EVENT_n_CFG(*counter_num), val, mask_val); - perfmon_counter_config(llcc_priv, EVENT_PORT_PMGR, counter_num); + perfmon_cntr_config(llcc_priv, EVENT_PORT_PMGR, *counter_num, enable); } static struct event_port_ops pmgr_port_ops = { @@ -1191,17 +1252,22 @@ static int llcc_perfmon_probe(struct platform_device *pdev) llcc_priv->llcc_map = llcc_driv_data->regmap; llcc_priv->llcc_bcast_map = llcc_driv_data->bcast_regmap; - llcc_bcast_read(llcc_priv, LLCC_COMMON_STATUS0, &val); llcc_priv->num_mc = (val & NUM_MC_MASK) >> NUM_MC_SHIFT; + /* Setting to 1, as some platforms it read as 0 */ + if (llcc_priv->num_mc == 0) + llcc_priv->num_mc = 1; + llcc_priv->num_banks = (val & LB_CNT_MASK) >> LB_CNT_SHIFT; for (val = 0; val < llcc_priv->num_banks; val++) llcc_priv->bank_off[val] = BANK_OFFSET * val; llcc_priv->version = REV_0; llcc_bcast_read(llcc_priv, LLCC_COMMON_HW_INFO, &val); - if (val >= LLCC_VERSION) + if (val == LLCC_VERSION_1) llcc_priv->version = REV_1; + else if (val == LLCC_VERSION_2) + llcc_priv->version = REV_2; result = sysfs_create_group(&pdev->dev.kobj, &llcc_perfmon_group); if (result) { @@ -1222,6 +1288,8 @@ static int llcc_perfmon_probe(struct platform_device *pdev) hrtimer_init(&llcc_priv->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); llcc_priv->hrtimer.function = llcc_perfmon_timer_handler; llcc_priv->expires = 0; + pr_info("Revision %d, has %d memory controllers connected with LLCC\n", + llcc_priv->version, llcc_priv->num_mc); return 0; } diff --git a/drivers/soc/qcom/llcc_perfmon.h b/drivers/soc/qcom/llcc_perfmon.h index 816e4c7126dd..4a3accda43e9 100644 --- a/drivers/soc/qcom/llcc_perfmon.h +++ b/drivers/soc/qcom/llcc_perfmon.h @@ -12,49 +12,50 @@ #define FEAC_PROF_FILTER_0_CFG3 (0x03700C) #define FEAC_PROF_FILTER_0_CFG5 (0x037014) #define FEAC_PROF_FILTER_0_CFG6 (0x037018) -#define FEAC_PROF_EVENT_n_CFG(n) (0x037060 + 4 * n) +#define FEAC_PROF_EVENT_n_CFG(n) (0x037060 + 4 * (n)) #define FEAC_PROF_CFG (0x0370A0) /* FERC */ #define FERC_PROF_FILTER_0_CFG0 (0x03B000) -#define FERC_PROF_EVENT_n_CFG(n) (0x03B020 + 4 * n) +#define FERC_PROF_EVENT_n_CFG(n) (0x03B020 + 4 * (n)) #define FERC_PROF_CFG (0x03B060) /* FEWC */ #define FEWC_PROF_FILTER_0_CFG0 (0x033000) -#define FEWC_PROF_EVENT_n_CFG(n) (0x033020 + 4 * n) +#define FEWC_PROF_EVENT_n_CFG(n) (0x033020 + 4 * (n)) /* BEAC */ #define BEAC_PROF_FILTER_0_CFG5 (0x049014) -#define BEAC_PROF_EVENT_n_CFG(n) (0x049040 + 4 * n) +#define BEAC_PROF_EVENT_n_CFG(n) (0x049040 + 4 * (n)) #define BEAC_PROF_CFG (0x049080) #define BEAC_INST_OFF (0x4000) /* BERC */ #define BERC_PROF_FILTER_0_CFG0 (0x039000) -#define BERC_PROF_EVENT_n_CFG(n) (0x039020 + 4 * n) +#define BERC_PROF_EVENT_n_CFG(n) (0x039020 + 4 * (n)) #define BERC_PROF_CFG (0x039060) /* TRP */ #define TRP_PROF_FILTER_0_CFG1 (0x024004) -#define TRP_PROF_EVENT_n_CFG(n) (0x024020 + 4 * n) -#define TRP_SCID_n_STATUS(n) (0x000004 + 0x1000 * n) +#define TRP_PROF_FILTER_0_CFG2 (0x024008) +#define TRP_PROF_EVENT_n_CFG(n) (0x024020 + 4 * (n)) +#define TRP_SCID_n_STATUS(n) (0x000004 + 0x1000 * (n)) /* DRP */ -#define DRP_PROF_EVENT_n_CFG(n) (0x044010 + 4 * n) +#define DRP_PROF_EVENT_n_CFG(n) (0x044010 + 4 * (n)) #define DRP_PROF_CFG (0x044050) /* PMGR */ -#define PMGR_PROF_EVENT_n_CFG(n) (0x03F000 + 4 * n) +#define PMGR_PROF_EVENT_n_CFG(n) (0x03F000 + 4 * (n)) -#define PERFMON_COUNTER_n_CONFIG(n) (0x031020 + 4 * n) +#define PERFMON_COUNTER_n_CONFIG(n) (0x031020 + 4 * (n)) #define PERFMON_MODE (0x03100C) #define PERFMON_DUMP (0x031010) -#define BROADCAST_COUNTER_n_VALUE(n) (0x031060 + 4 * n) +#define BROADCAST_COUNTER_n_VALUE(n) (0x031060 + 4 * (n)) -#define LLCC_COUNTER_n_VALUE(n) (0x031060 + 4 * n) +#define LLCC_COUNTER_n_VALUE(n) (0x031060 + 4 * (n)) -#define EVENT_NUM_MAX (64) +#define EVENT_NUM_MAX (128) #define SCID_MAX (32) /* Perfmon */ @@ -122,6 +123,8 @@ #define EVENT_SEL_SHIFT (0) #define EVENT_SEL_MASK GENMASK(EVENT_SEL_SHIFT + 5,\ EVENT_SEL_SHIFT) +#define EVENT_SEL_MASK7 GENMASK(EVENT_SEL_SHIFT + 6,\ + EVENT_SEL_SHIFT) #define CACHEALLOC_MASK_SHIFT (16) #define CACHEALLOC_MASK_MASK GENMASK(CACHEALLOC_MASK_SHIFT + 3, \ @@ -263,8 +266,10 @@ + 13, \ TRP_SCID_STATUS_CURRENT_CAP_SHIFT) -#define LLCC_VERSION (0x01010100) +#define LLCC_VERSION_1 (0x01010200) +#define LLCC_VERSION_2 (0x02000000) #define REV_0 (0x0) #define REV_1 (0x1) +#define REV_2 (0x2) #define BANK_OFFSET (0x80000) #endif /* _SOC_QCOM_LLCC_PERFMON_H_ */ From 7a47f5f9f0c4775971702c22f2e396e641ec7046 Mon Sep 17 00:00:00 2001 From: Avinash Philip Date: Fri, 23 Aug 2019 11:53:28 +0530 Subject: [PATCH 2/2] arm64: defconfig: Enable llcc perfmon drivers Enable llcc perfmon drivers for Lahaina SoC. Change-Id: I5f679dfac0f00b6be1dfaa60de9ce74e9a071b00 Signed-off-by: Avinash Philip --- arch/arm64/configs/vendor/lahaina_QGKI.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/lahaina_QGKI.config b/arch/arm64/configs/vendor/lahaina_QGKI.config index 9107aeffd8e3..89c85773bf95 100644 --- a/arch/arm64/configs/vendor/lahaina_QGKI.config +++ b/arch/arm64/configs/vendor/lahaina_QGKI.config @@ -14,3 +14,4 @@ CONFIG_ION_MSM_HEAPS=y CONFIG_IOMMU_IO_PGTABLE_FAST=y # CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST is not set # CONFIG_IOMMU_IO_PGTABLE_FAST_PROVE_TLB is not set +CONFIG_QCOM_LLCC_PERFMON=m