diff mbox series

[v3,03/11] spi: Lock controller idling transition inside the io_mutex

Message ID 20220621061234.3626638-4-david@protonic.nl (mailing list archive)
State Accepted
Commit c1038165fbbf83967f29b3bb38872faa780b3a72
Headers show
Series Optimize spi_sync path | expand

Commit Message

David Jander June 21, 2022, 6:12 a.m. UTC
This way, the spi sync path does not need to deal with the idling
transition.

Signed-off-by: David Jander <david@protonic.nl>
---
 drivers/spi/spi.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Comments

Andy Shevchenko June 21, 2022, 1:36 p.m. UTC | #1
On Tue, Jun 21, 2022 at 8:15 AM David Jander <david@protonic.nl> wrote:
>
> This way, the spi sync path does not need to deal with the idling
> transition.

...

> -       mutex_lock(&ctlr->io_mutex);
>         ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
>         mutex_unlock(&ctlr->io_mutex);
>
>         /* Prod the scheduler in case transfer_one() was busy waiting */

>         if (!ret)
>                 cond_resched();

In the similar way


ret = ...
if (ret)
  goto out_unlock;

mutex_unlock();
cond_resched();
return;

> +       return;
> +
> +out_unlock:
> +       mutex_unlock(&ctlr->io_mutex);
David Jander June 29, 2022, 1:08 p.m. UTC | #2
On Tue, 21 Jun 2022 15:36:23 +0200
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> On Tue, Jun 21, 2022 at 8:15 AM David Jander <david@protonic.nl> wrote:
> >
> > This way, the spi sync path does not need to deal with the idling
> > transition.  
> 
> ...
> 
> > -       mutex_lock(&ctlr->io_mutex);
> >         ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
> >         mutex_unlock(&ctlr->io_mutex);
> >
> >         /* Prod the scheduler in case transfer_one() was busy waiting */  
> 
> >         if (!ret)
> >                 cond_resched();  
> 
> In the similar way
> 
> 
> ret = ...
> if (ret)
>   goto out_unlock;
> 
> mutex_unlock();
> cond_resched();
> return;

Trying to add this change as an incremental patch to the whole series now that
it hit linux-next, I am not so sure about how to do this, since this code has
changed:

https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/spi/spi.c?id=dc3029056b02414c29b6627e3dd7b16624725ae9#n1729

I understand that the blank line at line 1730 should go after 1732, so that
the ret = ... and the if (!ret) kthread... are not separated by a blank line.

So far so good, but modifying the rest of the code into this "if (!ret)
goto..." idiom will mess that up, since the code in lines 1733 and 1734 is now
common to both paths, so the simplest way I see it is to move those two lines
in between the "ret = ..." and "if (!ret)...". Is that more desirable than not
having the "if (!ret) goto" idiom?

Code would look like this:

	ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
	ctlr->cur_msg = NULL;
	ctlr->fallback = false;
	if (!ret) {
		kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
		goto out_mutex;
	}

	mutex_unlock(&ctlr->io_mutex);

	/* Prod the scheduler in case transfer_one() was busy waiting */
	cond_resched();
	return;

out_unlock:
	spin_unlock_irqrestore(&ctlr->queue_lock, flags);
out_mutex:
	mutex_unlock(&ctlr->io_mutex);
}

Please advice: is this really more desirable to what it is now? Or can I
better leave it as is and only move the blank line?

> > +       return;
> > +
> > +out_unlock:
> > +       mutex_unlock(&ctlr->io_mutex);  
> 

Best regards,
diff mbox series

Patch

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 2d057d03c4f7..cfff2ff96fa0 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1643,27 +1643,30 @@  static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
 	unsigned long flags;
 	int ret;
 
+	/* Take the IO mutex */
+	mutex_lock(&ctlr->io_mutex);
+
 	/* Lock queue */
 	spin_lock_irqsave(&ctlr->queue_lock, flags);
 
 	/* Make sure we are not already running a message */
 	if (ctlr->cur_msg) {
 		spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-		return;
+		goto out_unlock;
 	}
 
 	/* If another context is idling the device then defer */
 	if (ctlr->idling) {
 		kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
 		spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-		return;
+		goto out_unlock;
 	}
 
 	/* Check if the queue is idle */
 	if (list_empty(&ctlr->queue) || !ctlr->running) {
 		if (!ctlr->busy) {
 			spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-			return;
+			goto out_unlock;
 		}
 
 		/* Defer any non-atomic teardown to the thread */
@@ -1679,7 +1682,7 @@  static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
 						   &ctlr->pump_messages);
 			}
 			spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-			return;
+			goto out_unlock;
 		}
 
 		ctlr->busy = false;
@@ -1701,7 +1704,7 @@  static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
 		ctlr->idling = false;
 		ctlr->queue_empty = true;
 		spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-		return;
+		goto out_unlock;
 	}
 
 	/* Extract head of queue */
@@ -1715,13 +1718,16 @@  static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
 		ctlr->busy = true;
 	spin_unlock_irqrestore(&ctlr->queue_lock, flags);
 
-	mutex_lock(&ctlr->io_mutex);
 	ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
 	mutex_unlock(&ctlr->io_mutex);
 
 	/* Prod the scheduler in case transfer_one() was busy waiting */
 	if (!ret)
 		cond_resched();
+	return;
+
+out_unlock:
+	mutex_unlock(&ctlr->io_mutex);
 }
 
 /**