RFC: Method for PM app to detect if any device is busy before deciding to use deep sleep policy

Thomas, Ramesh

Problem Statement:
Entering deep sleep states during pending device transactions can cause
transaction inconsistencies.

Why this is a problem:
When deep sleep state is entered, peripheral blocks are shutdown losing
state. If a transfer was ongoing when the block was turned off then the
state of the transaction would be left in an irrecoverably error state.
e.g. if the SPI block loses power when a SPI flash write was happening,
then parts of the flash memory would have been erased and written with
incomplete data.

When kernel idle task calls _sys_soc_suspend(), PM policy may decide to
enter deep sleep and calls .suspend() functions of devices. If a device
is busy at this point, one option for the driver is to return -EBUSY.
However, if it is discovered that a device is busy, after having
suspended several devices, then it could be suboptimal to roll back the
already suspended devices, or spend time retrying to get the busy
device to suspend.

Due to kernel idling logic which involves timer expiry calculations that
should not be interrupted, the kernel idle task disables interrupt
before going to idle. Since _sys_soc_suspend() is called in this context
with interrupts disabled, for it to block for too long, waiting for
devices to free up, would be disruptive to system scheduling.

What should be done:
A method for devices to register a busy state as follows:-

a)A bit field array with one bit per device will be used to store the
transaction status of each device.

b) "device_get_busy_list()" API will be called by PM app to retrieve a
pointer to the bit field array in (a) and use it to track device busy
status. Based on the transaction status of devices, PM app can decide
whether to enter deep sleep or any PM policy.

c) Device drivers will call "device_set_busy(struct device*)" API to
register beginning of a transaction that should not be interrupted by
deep sleep.

d) Device drivers will call "device_clear_busy(struct device*)" API to
clear the busy status of the device.