[PATCH] firmware: arm_scmi: Expose Perf protocol domains info

From: Cristian Marussi
Date: Mon Jan 29 2024 - 10:10:33 EST


Similarly to other existing SCMI protocols, expose Perf protocol domains
information to ease access from interested drivers and avoid adding an
endless stream of ad-hoc accessors.

Signed-off-by: Cristian Marussi <cristian.marussi@xxxxxxx>
---
Apply on sudeep/for-next/scmi/updates
---
drivers/firmware/arm_scmi/perf.c | 98 +++++++++------------------
drivers/firmware/arm_scmi/protocols.h | 13 ----
include/linux/scmi_protocol.h | 44 +++++++++++-
3 files changed, 76 insertions(+), 79 deletions(-)

diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 9e7b1ee94940..59089d212cbb 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -10,7 +10,6 @@
#include <linux/bits.h>
#include <linux/hashtable.h>
#include <linux/io.h>
-#include <linux/log2.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -27,8 +26,6 @@
/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x40000

-#define MAX_OPPS 32
-
enum scmi_performance_protocol_cmd {
PERF_DOMAIN_ATTRIBUTES = 0x3,
PERF_DESCRIBE_LEVELS = 0x4,
@@ -48,15 +45,6 @@ enum {
PERF_FC_MAX,
};

-struct scmi_opp {
- u32 perf;
- u32 power;
- u32 trans_latency_us;
- u32 indicative_freq;
- u32 level_index;
- struct hlist_node hash;
-};
-
struct scmi_msg_resp_perf_attributes {
__le16 num_domains;
__le16 flags;
@@ -145,25 +133,6 @@ struct scmi_msg_resp_perf_describe_levels_v4 {
} opp[];
};

-struct perf_dom_info {
- u32 id;
- bool set_limits;
- bool perf_limit_notify;
- bool perf_level_notify;
- bool perf_fastchannels;
- bool level_indexing_mode;
- u32 opp_count;
- u32 sustained_freq_khz;
- u32 sustained_perf_level;
- unsigned long mult_factor;
- struct scmi_perf_domain_info info;
- struct scmi_opp opp[MAX_OPPS];
- struct scmi_fc_info *fc_info;
- struct xarray opps_by_idx;
- struct xarray opps_by_lvl;
- DECLARE_HASHTABLE(opps_by_freq, ilog2(MAX_OPPS));
-};
-
#define LOOKUP_BY_FREQ(__htp, __freq) \
({ \
/* u32 cast is needed to pick right hash func */ \
@@ -182,7 +151,7 @@ struct scmi_perf_info {
enum scmi_power_scale power_scale;
u64 stats_addr;
u32 stats_size;
- struct perf_dom_info *dom_info;
+ struct scmi_perf_domain_info *dom_info;
};

static enum scmi_performance_protocol_cmd evt_2_cmd[] = {
@@ -238,7 +207,7 @@ static void scmi_perf_xa_destroy(void *data)

static int
scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *dom_info,
+ struct scmi_perf_domain_info *dom_info,
u32 version)
{
int ret;
@@ -259,7 +228,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
flags = le32_to_cpu(attr->flags);

dom_info->set_limits = SUPPORTS_SET_LIMITS(flags);
- dom_info->info.set_perf = SUPPORTS_SET_PERF_LVL(flags);
+ dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags);
dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags);
dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags);
dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
@@ -294,8 +263,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
"Wrong sustained perf/frequency(domain %d)\n",
dom_info->id);

- strscpy(dom_info->info.name, attr->name,
- SCMI_SHORT_NAME_MAX_SIZE);
+ strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
}

ph->xops->xfer_put(ph, t);
@@ -307,7 +275,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(flags))
ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET,
- dom_info->id, NULL, dom_info->info.name,
+ dom_info->id, NULL, dom_info->name,
SCMI_MAX_STR_SIZE);

if (dom_info->level_indexing_mode) {
@@ -328,7 +296,7 @@ static int opp_cmp_func(const void *opp1, const void *opp2)

struct scmi_perf_ipriv {
u32 version;
- struct perf_dom_info *perf_dom;
+ struct scmi_perf_domain_info *perf_dom;
};

static void iter_perf_levels_prepare_message(void *message,
@@ -365,7 +333,7 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx,
}

static inline void
-process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
+process_response_opp_v4(struct device *dev, struct scmi_perf_domain_info *dom,
struct scmi_opp *opp, unsigned int loop_idx,
const struct scmi_msg_resp_perf_describe_levels_v4 *r)
{
@@ -423,7 +391,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,

static int
scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *perf_dom, u32 version)
+ struct scmi_perf_domain_info *perf_dom, u32 version)
{
int ret;
void *iter;
@@ -437,7 +405,7 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph,
.perf_dom = perf_dom,
};

- iter = ph->hops->iter_response_init(ph, &ops, MAX_OPPS,
+ iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_OPPS,
PERF_DESCRIBE_LEVELS,
sizeof(struct scmi_msg_perf_describe_levels),
&ppriv);
@@ -462,7 +430,7 @@ static int scmi_perf_num_domains_get(const struct scmi_protocol_handle *ph)
return pi->num_domains;
}

-static inline struct perf_dom_info *
+static inline struct scmi_perf_domain_info *
scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain)
{
struct scmi_perf_info *pi = ph->get_priv(ph);
@@ -474,15 +442,15 @@ scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain)
}

static const struct scmi_perf_domain_info *
-scmi_perf_info_get(const struct scmi_protocol_handle *ph, u32 domain)
+scmi_perf_domain_info_get(const struct scmi_protocol_handle *ph, u32 domain)
{
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
return ERR_PTR(-EINVAL);

- return &dom->info;
+ return dom;
}

static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph,
@@ -509,7 +477,7 @@ static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph,
}

static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *dom, u32 max_perf,
+ struct scmi_perf_domain_info *dom, u32 max_perf,
u32 min_perf)
{
if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].set_addr) {
@@ -530,7 +498,7 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
u32 domain, u32 max_perf, u32 min_perf)
{
struct scmi_perf_info *pi = ph->get_priv(ph);
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -592,7 +560,7 @@ static int scmi_perf_msg_limits_get(const struct scmi_protocol_handle *ph,
}

static int __scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *dom, u32 *max_perf,
+ struct scmi_perf_domain_info *dom, u32 *max_perf,
u32 *min_perf)
{
if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].get_addr) {
@@ -612,7 +580,7 @@ static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
u32 domain, u32 *max_perf, u32 *min_perf)
{
int ret;
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -664,7 +632,7 @@ static int scmi_perf_msg_level_set(const struct scmi_protocol_handle *ph,
}

static int __scmi_perf_level_set(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *dom, u32 level,
+ struct scmi_perf_domain_info *dom, u32 level,
bool poll)
{
if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr) {
@@ -683,13 +651,13 @@ static int __scmi_perf_level_set(const struct scmi_protocol_handle *ph,
static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
u32 domain, u32 level, bool poll)
{
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
return PTR_ERR(dom);

- if (!dom->info.set_perf)
+ if (!dom->set_perf)
return -EOPNOTSUPP;

if (dom->level_indexing_mode) {
@@ -728,7 +696,7 @@ static int scmi_perf_msg_level_get(const struct scmi_protocol_handle *ph,
}

static int __scmi_perf_level_get(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *dom, u32 *level,
+ struct scmi_perf_domain_info *dom, u32 *level,
bool poll)
{
if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].get_addr) {
@@ -745,7 +713,7 @@ static int scmi_perf_level_get(const struct scmi_protocol_handle *ph,
u32 domain, u32 *level, bool poll)
{
int ret;
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -791,7 +759,7 @@ static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
}

static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *dom)
+ struct scmi_perf_domain_info *dom)
{
struct scmi_fc_info *fc;

@@ -807,7 +775,7 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
PERF_LIMITS_GET, 8, dom->id,
&fc[PERF_FC_LIMIT].get_addr, NULL);

- if (dom->info.set_perf)
+ if (dom->set_perf)
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
PERF_LEVEL_SET, 4, dom->id,
&fc[PERF_FC_LEVEL].set_addr,
@@ -828,7 +796,7 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
int idx, ret;
unsigned long freq;
struct dev_pm_opp_data data = {};
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -851,7 +819,7 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
}

dev_dbg(dev, "[%d][%s]:: Registered OPP[%d] %lu\n",
- domain, dom->info.name, idx, freq);
+ domain, dom->name, idx, freq);
}
return 0;
}
@@ -860,7 +828,7 @@ static int
scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph,
u32 domain)
{
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -874,7 +842,7 @@ static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
unsigned long freq, bool poll)
{
unsigned int level;
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -901,7 +869,7 @@ static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain,
{
int ret;
u32 level;
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -930,7 +898,7 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
u32 domain, unsigned long *freq,
unsigned long *power)
{
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;
unsigned long opp_freq;
int idx, ret = -EINVAL;
struct scmi_opp *opp;
@@ -960,7 +928,7 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
u32 domain)
{
- struct perf_dom_info *dom;
+ struct scmi_perf_domain_info *dom;

dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
@@ -979,7 +947,7 @@ scmi_power_scale_get(const struct scmi_protocol_handle *ph)

static const struct scmi_perf_proto_ops perf_proto_ops = {
.num_domains_get = scmi_perf_num_domains_get,
- .info_get = scmi_perf_info_get,
+ .info_get = scmi_perf_domain_info_get,
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
.level_set = scmi_perf_level_set,
@@ -1123,7 +1091,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
return -ENOMEM;

for (domain = 0; domain < pinfo->num_domains; domain++) {
- struct perf_dom_info *dom = pinfo->dom_info + domain;
+ struct scmi_perf_domain_info *dom = pinfo->dom_info + domain;

dom->id = domain;
scmi_perf_domain_attributes_get(ph, dom, version);
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index e683c26f24eb..cecb9b8f7faa 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -223,19 +223,6 @@ struct scmi_iterator_ops {
struct scmi_iterator_state *st, void *priv);
};

-struct scmi_fc_db_info {
- int width;
- u64 set;
- u64 mask;
- void __iomem *addr;
-};
-
-struct scmi_fc_info {
- void __iomem *set_addr;
- void __iomem *get_addr;
- struct scmi_fc_db_info *set_db;
-};
-
/**
* struct scmi_proto_helpers_ops - References to common protocol helpers
* @extended_name_get: A common helper function to retrieve extended naming
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 0cc40af5519a..e0e79ce297b2 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -10,8 +10,11 @@

#include <linux/bitfield.h>
#include <linux/device.h>
+#include <linux/hashtable.h>
+#include <linux/log2.h>
#include <linux/notifier.h>
#include <linux/types.h>
+#include <linux/xarray.h>

#define SCMI_MAX_STR_SIZE 64
#define SCMI_SHORT_NAME_MAX_SIZE 16
@@ -115,9 +118,48 @@ struct scmi_clk_proto_ops {
int (*parent_set)(const struct scmi_protocol_handle *ph, u32 clk_id, u32 parent_id);
};

+#define SCMI_MAX_OPPS 32
+
+struct scmi_opp {
+ u32 perf;
+ u32 power;
+ u32 trans_latency_us;
+ u32 indicative_freq;
+ u32 level_index;
+ struct hlist_node hash;
+};
+
+struct scmi_fc_db_info {
+ int width;
+ u64 set;
+ u64 mask;
+ void __iomem *addr;
+};
+
+struct scmi_fc_info {
+ void __iomem *set_addr;
+ void __iomem *get_addr;
+ struct scmi_fc_db_info *set_db;
+};
+
struct scmi_perf_domain_info {
- char name[SCMI_MAX_STR_SIZE];
+ u32 id;
+ bool set_limits;
bool set_perf;
+ bool perf_limit_notify;
+ bool perf_level_notify;
+ bool perf_fastchannels;
+ bool level_indexing_mode;
+ u32 opp_count;
+ u32 sustained_freq_khz;
+ u32 sustained_perf_level;
+ unsigned long mult_factor;
+ char name[SCMI_MAX_STR_SIZE];
+ struct scmi_opp opp[SCMI_MAX_OPPS];
+ struct scmi_fc_info *fc_info;
+ struct xarray opps_by_idx;
+ struct xarray opps_by_lvl;
+ DECLARE_HASHTABLE(opps_by_freq, ilog2(SCMI_MAX_OPPS));
};

/**
--
2.43.0