Commit d24b50e9 authored by Yongxu Wang's avatar Yongxu Wang Committed by Fabio Baltieri
Browse files

drivers: scmi: add use_polling parameter in scmi_send_message



SCMI supports both polling and interrupt modes for message completion.
Previously, the scmi_send_message() API used a 'pre_kernel' flag to
determine which mode to use_polling during the pre-kernel phase and
interrupts post-kernel.

This approach tightly coupled the decision logic with kernel state,
limiting flexibility. In particular, certain power management (PM)
related SCMI APIs require polling mode even in post-kernel context
to avoid unintended CPU wakeups caused by interrupts.

This patch replaces the 'pre_kernel' with a more generic
'use_polling' parameter, allowing callers to explicitly specify
the desired behavior. Typical usage can still rely on k_is_pre_kernel()
to determine polling mode in higher level api, while PM related
calls can directly enforce polling regardless of kernel state.

Signed-off-by: default avatarYongxu Wang <yongxu.wang@nxp.com>
parent 8843fd9f
Loading
Loading
Loading
Loading
+25 −6
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include <zephyr/drivers/firmware/scmi/clk.h>
#include <string.h>
#include <zephyr/kernel.h>

/* TODO: if extended attributes are supported this should be moved
 * to the header file so that users will have access to it.
@@ -38,6 +39,7 @@ int scmi_clock_rate_get(struct scmi_protocol *proto,
	struct scmi_message msg, reply;
	int ret;
	struct scmi_clock_rate_set_reply reply_buffer;
	bool use_polling;

	/* sanity checks */
	if (!proto || !rate) {
@@ -57,7 +59,9 @@ int scmi_clock_rate_get(struct scmi_protocol *proto,
	reply.len = sizeof(reply_buffer);
	reply.content = &reply_buffer;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
@@ -75,6 +79,7 @@ int scmi_clock_rate_set(struct scmi_protocol *proto, struct scmi_clock_rate_conf
{
	struct scmi_message msg, reply;
	int status, ret;
	bool use_polling;

	/* sanity checks */
	if (!proto || !cfg) {
@@ -98,7 +103,9 @@ int scmi_clock_rate_set(struct scmi_protocol *proto, struct scmi_clock_rate_conf
	reply.len = sizeof(status);
	reply.content = &status;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
@@ -115,6 +122,7 @@ int scmi_clock_parent_get(struct scmi_protocol *proto, uint32_t clk_id, uint32_t
	struct scmi_message msg, reply;
	int ret;
	struct scmi_clock_parent_get_reply reply_buffer;
	bool use_polling;

	/* sanity checks */
	if (!proto || !parent_id) {
@@ -134,7 +142,9 @@ int scmi_clock_parent_get(struct scmi_protocol *proto, uint32_t clk_id, uint32_t
	reply.len = sizeof(reply_buffer);
	reply.content = &reply_buffer;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
@@ -153,6 +163,7 @@ int scmi_clock_parent_set(struct scmi_protocol *proto, uint32_t clk_id, uint32_t
	struct scmi_clock_parent_config cfg = {.clk_id = clk_id, .parent_id = parent_id};
	struct scmi_message msg, reply;
	int status, ret;
	bool use_polling;

	/* sanity checks */
	if (!proto) {
@@ -172,7 +183,9 @@ int scmi_clock_parent_set(struct scmi_protocol *proto, uint32_t clk_id, uint32_t
	reply.len = sizeof(status);
	reply.content = &status;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
@@ -189,6 +202,7 @@ int scmi_clock_config_set(struct scmi_protocol *proto,
{
	struct scmi_message msg, reply;
	int status, ret;
	bool use_polling;

	/* sanity checks */
	if (!proto || !cfg) {
@@ -223,7 +237,9 @@ int scmi_clock_config_set(struct scmi_protocol *proto,
	reply.len = sizeof(status);
	reply.content = &status;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
@@ -240,6 +256,7 @@ int scmi_clock_protocol_attributes(struct scmi_protocol *proto, uint32_t *attrib
	struct scmi_message msg, reply;
	struct scmi_clock_attributes_reply reply_buffer;
	int ret;
	bool use_polling;

	/* sanity checks */
	if (!proto || !attributes) {
@@ -260,7 +277,9 @@ int scmi_clock_protocol_attributes(struct scmi_protocol *proto, uint32_t *attrib
	reply.len = sizeof(reply_buffer);
	reply.content = &reply_buffer;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
+9 −6
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ static int scmi_core_setup_chan(const struct device *transport,
	return 0;
}

static int scmi_send_message_pre_kernel(struct scmi_protocol *proto,
static int scmi_send_message_polling(struct scmi_protocol *proto,
					struct scmi_message *msg,
					struct scmi_message *reply)
{
@@ -103,6 +103,9 @@ static int scmi_send_message_pre_kernel(struct scmi_protocol *proto,
	 * Cortex-M quirk: no interrupts at this point => no timer =>
	 * no timeout mechanism => this can block the whole system.
	 *
	 * Polling mode repeatedly checks the chan_status field in share memory
	 * to detect whether the remote side have completed message processing
	 *
	 * TODO: is there a better way to handle this?
	 */
	while (!scmi_transport_channel_is_free(proto->transport, proto->tx)) {
@@ -116,7 +119,7 @@ static int scmi_send_message_pre_kernel(struct scmi_protocol *proto,
	return ret;
}

static int scmi_send_message_post_kernel(struct scmi_protocol *proto,
static int scmi_send_message_interrupt(struct scmi_protocol *proto,
					 struct scmi_message *msg,
					 struct scmi_message *reply)
{
@@ -159,7 +162,7 @@ out_release_mutex:
}

int scmi_send_message(struct scmi_protocol *proto, struct scmi_message *msg,
		      struct scmi_message *reply)
		      struct scmi_message *reply, bool use_polling)
{
	if (!proto->tx) {
		return -ENODEV;
@@ -169,10 +172,10 @@ int scmi_send_message(struct scmi_protocol *proto, struct scmi_message *msg,
		return -EINVAL;
	}

	if (k_is_pre_kernel()) {
		return scmi_send_message_pre_kernel(proto, msg, reply);
	if (use_polling) {
		return scmi_send_message_polling(proto, msg, reply);
	} else {
		return scmi_send_message_post_kernel(proto, msg, reply);
		return scmi_send_message_interrupt(proto, msg, reply);
	}
}

+8 −1
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include <string.h>
#include <zephyr/drivers/firmware/scmi/nxp/cpu.h>
#include <zephyr/kernel.h>

DT_SCMI_PROTOCOL_DEFINE_NODEV(DT_INST(0, nxp_scmi_cpu), NULL);

@@ -14,6 +15,7 @@ int scmi_cpu_sleep_mode_set(struct scmi_cpu_sleep_mode_config *cfg)
	struct scmi_protocol *proto = &SCMI_PROTOCOL_NAME(SCMI_PROTOCOL_CPU_DOMAIN);
	struct scmi_message msg, reply;
	int status, ret;
	bool use_polling;

	/* sanity checks */
	if (!proto || !cfg) {
@@ -33,7 +35,12 @@ int scmi_cpu_sleep_mode_set(struct scmi_cpu_sleep_mode_config *cfg)
	reply.len = sizeof(status);
	reply.content = &status;

	ret = scmi_send_message(proto, &msg, &reply);
	/* Set the PM-related scmi api to use poll mode to ensure that
	 * the CPU is not woken up by unnecessary scmi interrupts
	 */
	use_polling = true;

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
+5 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 */

#include <zephyr/drivers/firmware/scmi/pinctrl.h>
#include <zephyr/kernel.h>

DT_SCMI_PROTOCOL_DEFINE_NODEV(DT_INST(0, arm_scmi_pinctrl), NULL);

@@ -14,6 +15,7 @@ int scmi_pinctrl_settings_configure(struct scmi_pinctrl_settings *settings)
	struct scmi_message msg, reply;
	uint32_t config_num;
	int32_t status, ret;
	bool use_polling;

	proto = &SCMI_PROTOCOL_NAME(SCMI_PROTOCOL_PINCTRL);

@@ -50,7 +52,9 @@ int scmi_pinctrl_settings_configure(struct scmi_pinctrl_settings *settings)
	reply.len = sizeof(status);
	reply.content = &status;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
+9 −2
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include <zephyr/drivers/firmware/scmi/power.h>
#include <string.h>
#include <zephyr/kernel.h>

DT_SCMI_PROTOCOL_DEFINE_NODEV(DT_INST(0, arm_scmi_power), NULL);

@@ -20,6 +21,7 @@ int scmi_power_state_get(uint32_t domain_id, uint32_t *power_state)
	struct scmi_power_state_get_reply reply_buffer;
	struct scmi_message msg, reply;
	int ret;
	bool use_polling;

	/* sanity checks */
	if (!proto || !power_state) {
@@ -39,7 +41,9 @@ int scmi_power_state_get(uint32_t domain_id, uint32_t *power_state)
	reply.len = sizeof(reply_buffer);
	reply.content = &reply_buffer;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
@@ -58,6 +62,7 @@ int scmi_power_state_set(struct scmi_power_state_config *cfg)
	struct scmi_protocol *proto = &SCMI_PROTOCOL_NAME(SCMI_PROTOCOL_POWER_DOMAIN);
	struct scmi_message msg, reply;
	int status, ret;
	bool use_polling;

	/* sanity checks */
	if (!proto || !cfg) {
@@ -82,7 +87,9 @@ int scmi_power_state_set(struct scmi_power_state_config *cfg)
	reply.len = sizeof(status);
	reply.content = &status;

	ret = scmi_send_message(proto, &msg, &reply);
	use_polling = k_is_pre_kernel();

	ret = scmi_send_message(proto, &msg, &reply, use_polling);
	if (ret < 0) {
		return ret;
	}
Loading