diff mbox series

[v2,1/5] firmware: arm_scmi: Add discovery of SCMI v2.0 performance fastchannels

Message ID 20190806170208.6787-2-sudeep.holla@arm.com
State Accepted
Commit ac8aaf348cf54a07aff8e709329ef82ecfa230cc
Headers show
Series firmware: arm_scmi: add SCMI v2.0 fastchannels and reset protocol support | expand

Commit Message

Sudeep Holla Aug. 6, 2019, 5:02 p.m. UTC
SCMI v2.0 adds support for "FastChannel", a lightweight unidirectional
channel that is dedicated to a single SCMI message type for controlling
a specific platform resource. They do not use a message header as they
are specialized for a single message.

Only PERFORMANCE_LIMITS_{SET,GET} and PERFORMANCE_LEVEL_{SET,GET}
commands are supported over fastchannels. As they are optional, they
need to be discovered by PERFORMANCE_DESCRIBE_FASTCHANNEL command.
Further {LIMIT,LEVEL}_SET commands can have optional doorbell support.

Add support for discovery of these fastchannels.

Cc: Ionela Voinescu <Ionela.Voinescu@arm.com>
Cc: Chris Redpath <Chris.Redpath@arm.com>
Cc: Quentin Perret <Quentin.Perret@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

---
 drivers/firmware/arm_scmi/perf.c | 153 ++++++++++++++++++++++++++++++-
 1 file changed, 149 insertions(+), 4 deletions(-)

-- 
2.17.1

Comments

Peng Fan Aug. 7, 2019, 9:23 a.m. UTC | #1
> Subject: [PATCH v2 1/5] firmware: arm_scmi: Add discovery of SCMI v2.0

> performance fastchannels

> 

> SCMI v2.0 adds support for "FastChannel", a lightweight unidirectional

> channel that is dedicated to a single SCMI message type for controlling a

> specific platform resource. They do not use a message header as they are

> specialized for a single message.

> 

> Only PERFORMANCE_LIMITS_{SET,GET} and

> PERFORMANCE_LEVEL_{SET,GET} commands are supported over

> fastchannels. As they are optional, they need to be discovered by

> PERFORMANCE_DESCRIBE_FASTCHANNEL command.

> Further {LIMIT,LEVEL}_SET commands can have optional doorbell support.

> 

> Add support for discovery of these fastchannels.

> 

> Cc: Ionela Voinescu <Ionela.Voinescu@arm.com>

> Cc: Chris Redpath <Chris.Redpath@arm.com>

> Cc: Quentin Perret <Quentin.Perret@arm.com>

> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

> ---

>  drivers/firmware/arm_scmi/perf.c | 153

> ++++++++++++++++++++++++++++++-

>  1 file changed, 149 insertions(+), 4 deletions(-)

> 

> diff --git a/drivers/firmware/arm_scmi/perf.c

> b/drivers/firmware/arm_scmi/perf.c

> index 3c8ae7cc35de..6cce3e82e81e 100644

> --- a/drivers/firmware/arm_scmi/perf.c

> +++ b/drivers/firmware/arm_scmi/perf.c

> @@ -5,7 +5,9 @@

>   * Copyright (C) 2018 ARM Ltd.

>   */

> 

> +#include <linux/bits.h>

>  #include <linux/of.h>

> +#include <linux/io.h>

>  #include <linux/platform_device.h>

>  #include <linux/pm_opp.h>

>  #include <linux/sort.h>

> @@ -21,6 +23,7 @@ enum scmi_performance_protocol_cmd {

>  	PERF_LEVEL_GET = 0x8,

>  	PERF_NOTIFY_LIMITS = 0x9,

>  	PERF_NOTIFY_LEVEL = 0xa,

> +	PERF_DESCRIBE_FASTCHANNEL = 0xb,

>  };

> 

>  struct scmi_opp {

> @@ -44,6 +47,7 @@ struct scmi_msg_resp_perf_domain_attributes {

>  #define SUPPORTS_SET_PERF_LVL(x)	((x) & BIT(30))

>  #define SUPPORTS_PERF_LIMIT_NOTIFY(x)	((x) & BIT(29))

>  #define SUPPORTS_PERF_LEVEL_NOTIFY(x)	((x) & BIT(28))

> +#define SUPPORTS_PERF_FASTCHANNELS(x)	((x) & BIT(27))

>  	__le32 rate_limit_us;

>  	__le32 sustained_freq_khz;

>  	__le32 sustained_perf_level;

> @@ -87,17 +91,56 @@ struct scmi_msg_resp_perf_describe_levels {

>  	} opp[0];

>  };

> 

> +struct scmi_perf_get_fc_info {

> +	__le32 domain;

> +	__le32 message_id;

> +};

> +

> +struct scmi_msg_resp_perf_desc_fc {

> +	__le32 attr;

> +#define SUPPORTS_DOORBELL(x)		((x) & BIT(0))

> +#define DOORBELL_REG_WIDTH(x)		FIELD_GET(GENMASK(2, 1), (x))

> +	__le32 rate_limit;

> +	__le32 chan_addr_low;

> +	__le32 chan_addr_high;

> +	__le32 chan_size;

> +	__le32 db_addr_low;

> +	__le32 db_addr_high;

> +	__le32 db_set_lmask;

> +	__le32 db_set_hmask;

> +	__le32 db_preserve_lmask;

> +	__le32 db_preserve_hmask;

> +};

> +

> +struct scmi_fc_db_info {

> +	int width;

> +	u64 set;

> +	u64 mask;

> +	void __iomem *addr;

> +};

> +

> +struct scmi_fc_info {

> +	void __iomem *level_set_addr;

> +	void __iomem *limit_set_addr;

> +	void __iomem *level_get_addr;

> +	void __iomem *limit_get_addr;

> +	struct scmi_fc_db_info *level_set_db;

> +	struct scmi_fc_db_info *limit_set_db;

> +};

> +

>  struct perf_dom_info {

>  	bool set_limits;

>  	bool set_perf;

>  	bool perf_limit_notify;

>  	bool perf_level_notify;

> +	bool perf_fastchannels;

>  	u32 opp_count;

>  	u32 sustained_freq_khz;

>  	u32 sustained_perf_level;

>  	u32 mult_factor;

>  	char name[SCMI_MAX_STR_SIZE];

>  	struct scmi_opp opp[MAX_OPPS];

> +	struct scmi_fc_info *fc_info;

>  };

> 

>  struct scmi_perf_info {

> @@ -162,6 +205,7 @@ scmi_perf_domain_attributes_get(const struct

> scmi_handle *handle, u32 domain,

>  		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);

>  		dom_info->sustained_freq_khz =

>  					le32_to_cpu(attr->sustained_freq_khz);

>  		dom_info->sustained_perf_level =

> @@ -250,7 +294,7 @@ scmi_perf_describe_levels_get(const struct

> scmi_handle *handle, u32 domain,  }

> 

>  static int scmi_perf_limits_set(const struct scmi_handle *handle, u32

> domain,

> -				u32 max_perf, u32 min_perf)

> +				   u32 max_perf, u32 min_perf)

>  {

>  	int ret;

>  	struct scmi_xfer *t;

> @@ -273,7 +317,7 @@ static int scmi_perf_limits_set(const struct

> scmi_handle *handle, u32 domain,  }

> 

>  static int scmi_perf_limits_get(const struct scmi_handle *handle, u32

> domain,

> -				u32 *max_perf, u32 *min_perf)

> +				   u32 *max_perf, u32 *min_perf)

>  {

>  	int ret;

>  	struct scmi_xfer *t;

> @@ -299,7 +343,7 @@ static int scmi_perf_limits_get(const struct

> scmi_handle *handle, u32 domain,  }

> 

>  static int scmi_perf_level_set(const struct scmi_handle *handle, u32

> domain,

> -			       u32 level, bool poll)

> +				  u32 level, bool poll)

>  {

>  	int ret;

>  	struct scmi_xfer *t;

> @@ -322,7 +366,7 @@ static int scmi_perf_level_set(const struct

> scmi_handle *handle, u32 domain,  }

> 

>  static int scmi_perf_level_get(const struct scmi_handle *handle, u32

> domain,

> -			       u32 *level, bool poll)

> +				  u32 *level, bool poll)

>  {

>  	int ret;

>  	struct scmi_xfer *t;

> @@ -343,6 +387,104 @@ static int scmi_perf_level_get(const struct

> scmi_handle *handle, u32 domain,

>  	return ret;

>  }

> 

> +static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size) {

> +	if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)

> +		return true;

> +	if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8)

> +		return true;

> +	return false;

> +}

> +

> +static void

> +scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,

> +			 u32 message_id, void __iomem **p_addr,

> +			 struct scmi_fc_db_info **p_db)

> +{

> +	int ret;

> +	u32 flags;

> +	u64 phys_addr;

> +	u8 size;

> +	void __iomem *addr;

> +	struct scmi_xfer *t;

> +	struct scmi_fc_db_info *db;

> +	struct scmi_perf_get_fc_info *info;

> +	struct scmi_msg_resp_perf_desc_fc *resp;

> +

> +	if (!p_addr)

> +		return;

> +

> +	ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_FASTCHANNEL,

> +				 SCMI_PROTOCOL_PERF,

> +				 sizeof(*info), sizeof(*resp), &t);

> +	if (ret)

> +		return;

> +

> +	info = t->tx.buf;

> +	info->domain = cpu_to_le32(domain);

> +	info->message_id = cpu_to_le32(message_id);

> +

> +	ret = scmi_do_xfer(handle, t);

> +	if (ret)

> +		goto err_xfer;

> +

> +	resp = t->rx.buf;

> +	flags = le32_to_cpu(resp->attr);

> +	size = le32_to_cpu(resp->chan_size);

> +	if (!scmi_perf_fc_size_is_valid(message_id, size))

> +		goto err_xfer;

> +

> +	phys_addr = le32_to_cpu(resp->chan_addr_low);

> +	phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;

> +	addr = devm_ioremap(handle->dev, phys_addr, size);

> +	if (!addr)

> +		goto err_xfer;

> +	*p_addr = addr;

> +

> +	if (p_db && SUPPORTS_DOORBELL(flags)) {

> +		db = devm_kzalloc(handle->dev, sizeof(*db), GFP_KERNEL);

> +		if (!db)

> +			goto err_xfer;

> +

> +		size = 1 << DOORBELL_REG_WIDTH(flags);

> +		phys_addr = le32_to_cpu(resp->db_addr_low);

> +		phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;

> +		addr = devm_ioremap(handle->dev, phys_addr, size);

> +		if (!addr)

> +			goto err_xfer;

> +

> +		db->addr = addr;

> +		db->width = size;

> +		db->set = le32_to_cpu(resp->db_set_lmask);

> +		db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;

> +		db->mask = le32_to_cpu(resp->db_preserve_lmask);

> +		db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;

> +		*p_db = db;

> +	}

> +err_xfer:

> +	scmi_xfer_put(handle, t);

> +}

> +

> +static void scmi_perf_domain_init_fc(const struct scmi_handle *handle,

> +				     u32 domain, struct scmi_fc_info **p_fc) {

> +	struct scmi_fc_info *fc;

> +

> +	fc = devm_kzalloc(handle->dev, sizeof(*fc), GFP_KERNEL);

> +	if (!fc)

> +		return;

> +

> +	scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_SET,

> +				 &fc->level_set_addr, &fc->level_set_db);

> +	scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_GET,

> +				 &fc->level_get_addr, NULL);

> +	scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_SET,

> +				 &fc->limit_set_addr, &fc->limit_set_db);

> +	scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_GET,

> +				 &fc->limit_get_addr, NULL);

> +	*p_fc = fc;

> +}

> +

>  /* Device specific ops */

>  static int scmi_dev_domain_id(struct device *dev)  { @@ -494,6 +636,9

> @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)

> 

>  		scmi_perf_domain_attributes_get(handle, domain, dom);

>  		scmi_perf_describe_levels_get(handle, domain, dom);

> +

> +		if (dom->perf_fastchannels)

> +			scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);

>  	}

> 

>  	handle->perf_ops = &perf_ops;


Reviewed-by: Peng Fan <peng.fan@nxp.com>


> --

> 2.17.1
Sudeep Holla Aug. 7, 2019, 10:28 a.m. UTC | #2
On Wed, Aug 07, 2019 at 09:23:41AM +0000, Peng Fan wrote:
> > Subject: [PATCH v2 1/5] firmware: arm_scmi: Add discovery of SCMI v2.0

> > performance fastchannels

> >

> > SCMI v2.0 adds support for "FastChannel", a lightweight unidirectional

> > channel that is dedicated to a single SCMI message type for controlling a

> > specific platform resource. They do not use a message header as they are

> > specialized for a single message.

> >

> > Only PERFORMANCE_LIMITS_{SET,GET} and

> > PERFORMANCE_LEVEL_{SET,GET} commands are supported over

> > fastchannels. As they are optional, they need to be discovered by

> > PERFORMANCE_DESCRIBE_FASTCHANNEL command.

> > Further {LIMIT,LEVEL}_SET commands can have optional doorbell support.

> >

> > Add support for discovery of these fastchannels.

> >

> > Cc: Ionela Voinescu <Ionela.Voinescu@arm.com>

> > Cc: Chris Redpath <Chris.Redpath@arm.com>

> > Cc: Quentin Perret <Quentin.Perret@arm.com>

> > Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

> > ---

> >  drivers/firmware/arm_scmi/perf.c | 153

> > ++++++++++++++++++++++++++++++-

> >  1 file changed, 149 insertions(+), 4 deletions(-)

> >


[...]

>

> Reviewed-by: Peng Fan <peng.fan@nxp.com>

>


Thanks for the review.

--
Regards,
Sudeep
diff mbox series

Patch

diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 3c8ae7cc35de..6cce3e82e81e 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -5,7 +5,9 @@ 
  * Copyright (C) 2018 ARM Ltd.
  */
 
+#include <linux/bits.h>
 #include <linux/of.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
 #include <linux/sort.h>
@@ -21,6 +23,7 @@  enum scmi_performance_protocol_cmd {
 	PERF_LEVEL_GET = 0x8,
 	PERF_NOTIFY_LIMITS = 0x9,
 	PERF_NOTIFY_LEVEL = 0xa,
+	PERF_DESCRIBE_FASTCHANNEL = 0xb,
 };
 
 struct scmi_opp {
@@ -44,6 +47,7 @@  struct scmi_msg_resp_perf_domain_attributes {
 #define SUPPORTS_SET_PERF_LVL(x)	((x) & BIT(30))
 #define SUPPORTS_PERF_LIMIT_NOTIFY(x)	((x) & BIT(29))
 #define SUPPORTS_PERF_LEVEL_NOTIFY(x)	((x) & BIT(28))
+#define SUPPORTS_PERF_FASTCHANNELS(x)	((x) & BIT(27))
 	__le32 rate_limit_us;
 	__le32 sustained_freq_khz;
 	__le32 sustained_perf_level;
@@ -87,17 +91,56 @@  struct scmi_msg_resp_perf_describe_levels {
 	} opp[0];
 };
 
+struct scmi_perf_get_fc_info {
+	__le32 domain;
+	__le32 message_id;
+};
+
+struct scmi_msg_resp_perf_desc_fc {
+	__le32 attr;
+#define SUPPORTS_DOORBELL(x)		((x) & BIT(0))
+#define DOORBELL_REG_WIDTH(x)		FIELD_GET(GENMASK(2, 1), (x))
+	__le32 rate_limit;
+	__le32 chan_addr_low;
+	__le32 chan_addr_high;
+	__le32 chan_size;
+	__le32 db_addr_low;
+	__le32 db_addr_high;
+	__le32 db_set_lmask;
+	__le32 db_set_hmask;
+	__le32 db_preserve_lmask;
+	__le32 db_preserve_hmask;
+};
+
+struct scmi_fc_db_info {
+	int width;
+	u64 set;
+	u64 mask;
+	void __iomem *addr;
+};
+
+struct scmi_fc_info {
+	void __iomem *level_set_addr;
+	void __iomem *limit_set_addr;
+	void __iomem *level_get_addr;
+	void __iomem *limit_get_addr;
+	struct scmi_fc_db_info *level_set_db;
+	struct scmi_fc_db_info *limit_set_db;
+};
+
 struct perf_dom_info {
 	bool set_limits;
 	bool set_perf;
 	bool perf_limit_notify;
 	bool perf_level_notify;
+	bool perf_fastchannels;
 	u32 opp_count;
 	u32 sustained_freq_khz;
 	u32 sustained_perf_level;
 	u32 mult_factor;
 	char name[SCMI_MAX_STR_SIZE];
 	struct scmi_opp opp[MAX_OPPS];
+	struct scmi_fc_info *fc_info;
 };
 
 struct scmi_perf_info {
@@ -162,6 +205,7 @@  scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
 		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);
 		dom_info->sustained_freq_khz =
 					le32_to_cpu(attr->sustained_freq_khz);
 		dom_info->sustained_perf_level =
@@ -250,7 +294,7 @@  scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
 }
 
 static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
-				u32 max_perf, u32 min_perf)
+				   u32 max_perf, u32 min_perf)
 {
 	int ret;
 	struct scmi_xfer *t;
@@ -273,7 +317,7 @@  static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
 }
 
 static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
-				u32 *max_perf, u32 *min_perf)
+				   u32 *max_perf, u32 *min_perf)
 {
 	int ret;
 	struct scmi_xfer *t;
@@ -299,7 +343,7 @@  static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
 }
 
 static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
-			       u32 level, bool poll)
+				  u32 level, bool poll)
 {
 	int ret;
 	struct scmi_xfer *t;
@@ -322,7 +366,7 @@  static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
 }
 
 static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
-			       u32 *level, bool poll)
+				  u32 *level, bool poll)
 {
 	int ret;
 	struct scmi_xfer *t;
@@ -343,6 +387,104 @@  static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
 	return ret;
 }
 
+static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
+{
+	if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)
+		return true;
+	if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8)
+		return true;
+	return false;
+}
+
+static void
+scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,
+			 u32 message_id, void __iomem **p_addr,
+			 struct scmi_fc_db_info **p_db)
+{
+	int ret;
+	u32 flags;
+	u64 phys_addr;
+	u8 size;
+	void __iomem *addr;
+	struct scmi_xfer *t;
+	struct scmi_fc_db_info *db;
+	struct scmi_perf_get_fc_info *info;
+	struct scmi_msg_resp_perf_desc_fc *resp;
+
+	if (!p_addr)
+		return;
+
+	ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_FASTCHANNEL,
+				 SCMI_PROTOCOL_PERF,
+				 sizeof(*info), sizeof(*resp), &t);
+	if (ret)
+		return;
+
+	info = t->tx.buf;
+	info->domain = cpu_to_le32(domain);
+	info->message_id = cpu_to_le32(message_id);
+
+	ret = scmi_do_xfer(handle, t);
+	if (ret)
+		goto err_xfer;
+
+	resp = t->rx.buf;
+	flags = le32_to_cpu(resp->attr);
+	size = le32_to_cpu(resp->chan_size);
+	if (!scmi_perf_fc_size_is_valid(message_id, size))
+		goto err_xfer;
+
+	phys_addr = le32_to_cpu(resp->chan_addr_low);
+	phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
+	addr = devm_ioremap(handle->dev, phys_addr, size);
+	if (!addr)
+		goto err_xfer;
+	*p_addr = addr;
+
+	if (p_db && SUPPORTS_DOORBELL(flags)) {
+		db = devm_kzalloc(handle->dev, sizeof(*db), GFP_KERNEL);
+		if (!db)
+			goto err_xfer;
+
+		size = 1 << DOORBELL_REG_WIDTH(flags);
+		phys_addr = le32_to_cpu(resp->db_addr_low);
+		phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
+		addr = devm_ioremap(handle->dev, phys_addr, size);
+		if (!addr)
+			goto err_xfer;
+
+		db->addr = addr;
+		db->width = size;
+		db->set = le32_to_cpu(resp->db_set_lmask);
+		db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
+		db->mask = le32_to_cpu(resp->db_preserve_lmask);
+		db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
+		*p_db = db;
+	}
+err_xfer:
+	scmi_xfer_put(handle, t);
+}
+
+static void scmi_perf_domain_init_fc(const struct scmi_handle *handle,
+				     u32 domain, struct scmi_fc_info **p_fc)
+{
+	struct scmi_fc_info *fc;
+
+	fc = devm_kzalloc(handle->dev, sizeof(*fc), GFP_KERNEL);
+	if (!fc)
+		return;
+
+	scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_SET,
+				 &fc->level_set_addr, &fc->level_set_db);
+	scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_GET,
+				 &fc->level_get_addr, NULL);
+	scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_SET,
+				 &fc->limit_set_addr, &fc->limit_set_db);
+	scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_GET,
+				 &fc->limit_get_addr, NULL);
+	*p_fc = fc;
+}
+
 /* Device specific ops */
 static int scmi_dev_domain_id(struct device *dev)
 {
@@ -494,6 +636,9 @@  static int scmi_perf_protocol_init(struct scmi_handle *handle)
 
 		scmi_perf_domain_attributes_get(handle, domain, dom);
 		scmi_perf_describe_levels_get(handle, domain, dom);
+
+		if (dom->perf_fastchannels)
+			scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);
 	}
 
 	handle->perf_ops = &perf_ops;