diff mbox series

[v7,06/16] firmware: arm_scmi: Add configurable polling mode for transports

Message ID 20211129191156.29322-7-cristian.marussi@arm.com (mailing list archive)
State New, archived
Headers show
Series Introduce atomic support for SCMI transports | expand

Commit Message

Cristian Marussi Nov. 29, 2021, 7:11 p.m. UTC
SCMI communications along TX channels can optionally be provided of a
completion interrupt; when such interrupt is not available, command
transactions should rely on polling, where the SCMI core takes care to
repeatedly evaluate the transport-specific .poll_done() function, if
available, to determine if and when a request was fully completed or
timed out.

Such mechanism is already present and working on a single transfer base:
SCMI protocols can indeed enable hdr.poll_completion on specific commands
ahead of each transfer and cause that transaction to be handled with
polling.

Introduce a couple of flags to be able to enforce such polling behaviour
globally at will:

 - scmi_desc.force_polling: to statically switch the whole transport to
   polling mode.

 - scmi_chan_info.no_completion_irq: to switch a single channel dynamically
   to polling mode if, at runtime, is determined that no completion
   interrupt was available for such channel.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v5 --> v6
- removed check on replies received by IRQs when xfer was requested
  as poll_completion (not all transport can suppress IRQs on an xfer basis)
v4 --> v5
- make force_polling const
- introduce polling_enabled flag to simplify checks on do_xfer
v3 --> v4:
- renamed .needs_polling flag to .no_completion_irq
- refactored error path when polling needed but not supported
---
 drivers/firmware/arm_scmi/common.h | 11 +++++++++++
 drivers/firmware/arm_scmi/driver.c | 17 +++++++++++++++++
 2 files changed, 28 insertions(+)

Comments

Sudeep Holla Dec. 13, 2021, 11:25 a.m. UTC | #1
On Mon, Nov 29, 2021 at 07:11:46PM +0000, Cristian Marussi wrote:
> SCMI communications along TX channels can optionally be provided of a
> completion interrupt; when such interrupt is not available, command
> transactions should rely on polling, where the SCMI core takes care to
> repeatedly evaluate the transport-specific .poll_done() function, if
> available, to determine if and when a request was fully completed or
> timed out.
> 
> Such mechanism is already present and working on a single transfer base:
> SCMI protocols can indeed enable hdr.poll_completion on specific commands
> ahead of each transfer and cause that transaction to be handled with
> polling.
> 
> Introduce a couple of flags to be able to enforce such polling behaviour
> globally at will:
> 
>  - scmi_desc.force_polling: to statically switch the whole transport to
>    polling mode.
> 
>  - scmi_chan_info.no_completion_irq: to switch a single channel dynamically
>    to polling mode if, at runtime, is determined that no completion
>    interrupt was available for such channel.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> v5 --> v6
> - removed check on replies received by IRQs when xfer was requested
>   as poll_completion (not all transport can suppress IRQs on an xfer basis)
> v4 --> v5
> - make force_polling const
> - introduce polling_enabled flag to simplify checks on do_xfer
> v3 --> v4:
> - renamed .needs_polling flag to .no_completion_irq
> - refactored error path when polling needed but not supported
> ---
>  drivers/firmware/arm_scmi/common.h | 11 +++++++++++
>  drivers/firmware/arm_scmi/driver.c | 17 +++++++++++++++++
>  2 files changed, 28 insertions(+)
> 
> diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
> index 6438b5248c24..99b74f4d39b6 100644
> --- a/drivers/firmware/arm_scmi/common.h
> +++ b/drivers/firmware/arm_scmi/common.h
> @@ -339,11 +339,19 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
>   * @dev: Reference to device in the SCMI hierarchy corresponding to this
>   *	 channel
>   * @handle: Pointer to SCMI entity handle
> + * @no_completion_irq: Flag to indicate that this channel has no completion
> + *		       interrupt mechanism for synchronous commands.
> + *		       This can be dynamically set by transports at run-time
> + *		       inside their provided .chan_setup().
> + * @polling_enabled: Flag used to annotate if polling mode is currently enabled
> + *		     on this channel.
>   * @transport_info: Transport layer related information
>   */
>  struct scmi_chan_info {
>  	struct device *dev;
>  	struct scmi_handle *handle;
> +	bool no_completion_irq;
> +	bool polling_enabled;

Do we really need a separate flag for polling_enabled ?
no_completion_irq means you need to enable polling and force_polling too.
Just trying to see if we can get rid of unnecessary flags.
Cristian Marussi Dec. 14, 2021, 10:49 a.m. UTC | #2
On Mon, Dec 13, 2021 at 11:25:55AM +0000, Sudeep Holla wrote:
> On Mon, Nov 29, 2021 at 07:11:46PM +0000, Cristian Marussi wrote:
> > SCMI communications along TX channels can optionally be provided of a
> > completion interrupt; when such interrupt is not available, command
> > transactions should rely on polling, where the SCMI core takes care to
> > repeatedly evaluate the transport-specific .poll_done() function, if
> > available, to determine if and when a request was fully completed or
> > timed out.
> > 

Hi Sudeep, 

thanks for the review.

> > Such mechanism is already present and working on a single transfer base:
> > SCMI protocols can indeed enable hdr.poll_completion on specific commands
> > ahead of each transfer and cause that transaction to be handled with
> > polling.
> > 
> > Introduce a couple of flags to be able to enforce such polling behaviour
> > globally at will:
> > 
> >  - scmi_desc.force_polling: to statically switch the whole transport to
> >    polling mode.
> > 
> >  - scmi_chan_info.no_completion_irq: to switch a single channel dynamically
> >    to polling mode if, at runtime, is determined that no completion
> >    interrupt was available for such channel.
> > 
> > Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> > ---
> > v5 --> v6
> > - removed check on replies received by IRQs when xfer was requested
> >   as poll_completion (not all transport can suppress IRQs on an xfer basis)
> > v4 --> v5
> > - make force_polling const
> > - introduce polling_enabled flag to simplify checks on do_xfer
> > v3 --> v4:
> > - renamed .needs_polling flag to .no_completion_irq
> > - refactored error path when polling needed but not supported
> > ---
> >  drivers/firmware/arm_scmi/common.h | 11 +++++++++++
> >  drivers/firmware/arm_scmi/driver.c | 17 +++++++++++++++++
> >  2 files changed, 28 insertions(+)
> > 
> > diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
> > index 6438b5248c24..99b74f4d39b6 100644
> > --- a/drivers/firmware/arm_scmi/common.h
> > +++ b/drivers/firmware/arm_scmi/common.h
> > @@ -339,11 +339,19 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
> >   * @dev: Reference to device in the SCMI hierarchy corresponding to this
> >   *	 channel
> >   * @handle: Pointer to SCMI entity handle
> > + * @no_completion_irq: Flag to indicate that this channel has no completion
> > + *		       interrupt mechanism for synchronous commands.
> > + *		       This can be dynamically set by transports at run-time
> > + *		       inside their provided .chan_setup().
> > + * @polling_enabled: Flag used to annotate if polling mode is currently enabled
> > + *		     on this channel.
> >   * @transport_info: Transport layer related information
> >   */
> >  struct scmi_chan_info {
> >  	struct device *dev;
> >  	struct scmi_handle *handle;
> > +	bool no_completion_irq;
> > +	bool polling_enabled;
> 
> Do we really need a separate flag for polling_enabled ?
> no_completion_irq means you need to enable polling and force_polling too.
> Just trying to see if we can get rid of unnecessary flags.
> 

Not really needed indeed, I was just trying to avoid multiple conditions
checks later on the TX path (given no_completion_irq and force_polling
never change after channel setup so I can just note down at setup that
polling is enabled and then just check that later) and improve readability,
but I can just use macros for readability and just ignore the multiple
unneeded checks.

Same holds later on the series for polling_capable flag that I similarly
setup early during probe to avoid unneeded multiple condition checks.

I'll remove both this internal flags and resort to macros, if it's fine
for you.

Thanks,
Cristian
diff mbox series

Patch

diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 6438b5248c24..99b74f4d39b6 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -339,11 +339,19 @@  void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
  * @dev: Reference to device in the SCMI hierarchy corresponding to this
  *	 channel
  * @handle: Pointer to SCMI entity handle
+ * @no_completion_irq: Flag to indicate that this channel has no completion
+ *		       interrupt mechanism for synchronous commands.
+ *		       This can be dynamically set by transports at run-time
+ *		       inside their provided .chan_setup().
+ * @polling_enabled: Flag used to annotate if polling mode is currently enabled
+ *		     on this channel.
  * @transport_info: Transport layer related information
  */
 struct scmi_chan_info {
 	struct device *dev;
 	struct scmi_handle *handle;
+	bool no_completion_irq;
+	bool polling_enabled;
 	void *transport_info;
 };
 
@@ -402,6 +410,8 @@  struct scmi_device *scmi_child_dev_find(struct device *parent,
  *	be pending simultaneously in the system. May be overridden by the
  *	get_max_msg op.
  * @max_msg_size: Maximum size of data per message that can be handled.
+ * @force_polling: Flag to force this whole transport to use SCMI core polling
+ *		   mechanism instead of completion interrupts even if available.
  */
 struct scmi_desc {
 	int (*transport_init)(void);
@@ -410,6 +420,7 @@  struct scmi_desc {
 	int max_rx_timeout_ms;
 	int max_msg;
 	int max_msg_size;
+	const bool force_polling;
 };
 
 #ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 476b91845e40..8a30b832899c 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -817,6 +817,7 @@  static int do_xfer(const struct scmi_protocol_handle *ph,
 	struct device *dev = info->dev;
 	struct scmi_chan_info *cinfo;
 
+	/* Check for polling request on custom command xfers at first */
 	if (xfer->hdr.poll_completion && !info->desc->ops->poll_done) {
 		dev_warn_once(dev,
 			      "Polling mode is not supported by transport.\n");
@@ -827,6 +828,10 @@  static int do_xfer(const struct scmi_protocol_handle *ph,
 	if (unlikely(!cinfo))
 		return -EINVAL;
 
+	/* Initialized to true ONLY if also supported by transport. */
+	if (cinfo->polling_enabled)
+		xfer->hdr.poll_completion = true;
+
 	/*
 	 * Initialise protocol id now from protocol handle to avoid it being
 	 * overridden by mistake (or malice) by the protocol code mangling with
@@ -1527,6 +1532,18 @@  static int scmi_chan_setup(struct scmi_info *info, struct device *dev,
 	if (ret)
 		return ret;
 
+	if (tx && (cinfo->no_completion_irq || info->desc->force_polling)) {
+		if (info->desc->ops->poll_done) {
+			dev_info(dev,
+				 "Enabled polling mode TX channel - prot_id:%d\n",
+				 prot_id);
+			cinfo->polling_enabled = true;
+		} else {
+			dev_warn(dev,
+				 "Polling mode NOT supported by transport.\n");
+		}
+	}
+
 idr_alloc:
 	ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL);
 	if (ret != prot_id) {