Re: Regression: spi: core: avoid waking pump thread from spi_sync instead run teardown delayed

From: kernel
Date: Fri Jan 18 2019 - 12:11:38 EST


Hi Mark!

Just got access to my computer back for the weekend ;)

> On 15.01.2019, at 22:25, Mark Brown <broonie@xxxxxxxxxx> wrote:
>
> On Tue, Jan 15, 2019 at 09:58:55PM +0100, Martin Sperl wrote:
>
>> I may find some time over the weekend if no solution
>> has been found until then.
>
> Thanks for volunteering :)

I actually brought this about so I see is as part of my
responsibility trying to solve the issue as well...
>
>> The way I would envision it it would have a âstateâ
>> as a level (0=shutdown, 1=hw enabled, 2=in pump,
>> 3=in transfer, 4=in hw-mode,...) and a complete
>> to allow waking the shutdown thread (and by this
>> avoiding the busy wait loop we have now).
>> This would replace those idling, busy, and running flags.
>
> That's a good idea, yes - a single enum much more reflects what we can
> actually do in terms of transitions.

Does something like this looks acceptable?

diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index ec210286567c..677fc5025033 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -288,6 +288,21 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
module_driver(__spi_driver, spi_register_driver, \
spi_unregister_driver)

+/* define SPI Controller states in the state machine */
+enum spi_controller_state {
+ SPI_CONTROLLER_STATE_SHUTDOWN = 0,
+ SPI_CONTROLLER_STATE_IDLE = 1,
+ SPI_CONTROLLER_STATE_IN_PROCESS = 2,
+ SPI_CONTROLLER_STATE_IN_TRANSFER = 3,
+};
+
+/* define SPI Controller mode */
+enum spi_controller_mode {
+ SPI_CONTROLLER_MODE_NORMAL = 0, /* normal spi mode */
+ SPI_CONTROLLER_MODE_MEM = 1, /* memory mode using mem_ops */
+ SPI_CONTROLLER_MODE_EXCLUSIVE = 2, /* could replace bus_lock_flag */
+};
+
/**
* struct spi_controller - interface to SPI master or slave controller
* @dev: device interface to this driver
@@ -332,14 +347,16 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @pump_idle_teardown: work structure for scheduling a teardown delayed
* @queue_lock: spinlock to syncronise access to message queue
* @queue: message queue
- * @idling: the device is entering idle state
* @cur_msg: the currently in-flight message
* @cur_msg_prepared: spi_prepare_message was called for the currently
* in-flight message
* @cur_msg_mapped: message has been mapped for DMA
+ * @controller_state: defines the current state of the controller
+ * state machine
+ * @controller_state_changed: wakeup of threads interrested in getting
+ * notified about a mode change (primarily pm)
+ * @controller_mode: defines the current mode of the controller
* @xfer_completion: used by core transfer_one_message()
- * @busy: message pump is busy
- * @running: message pump is running
* @rt: whether this queue is set to run as a realtime task
* @auto_runtime_pm: the core should ensure a runtime PM reference is held
* while the hardware is prepared, using the parent
@@ -524,9 +541,9 @@ struct spi_controller {
spinlock_t queue_lock;
struct list_head queue;
struct spi_message *cur_msg;
- bool idling;
- bool busy;
- bool running;
+ enum spi_controller_state controller_state;
+ struct completion controller_state_changed;
+ enum spi_controller_mode controller_mode;
bool rt;
bool auto_runtime_pm;
bool cur_msg_prepared;


SPI_CONTROLLER_MODE_EXCLUSIVE could replace the bus_lock_flag.
I am also not sure of the âconventionâ of memory mode (i.e
using mem_ops). Is it maybe implicitly spi_bus_locked - i.e
typically only a single device?

Essentially we would transition between these states linearly
(hopefully no jumps are needed).

Martin