New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
storage: flash_map: PM in flash_area_open/close
#60709
storage: flash_map: PM in flash_area_open/close
#60709
Conversation
Run power management actions in `flash_area_open` and `flash_area_close`. If the flash area is open it should be in the active state, otherwise it should be left in its lowest power state. Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
Test the new behaviour of claiming backing devices in open/close. Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
@JordanYates, is it required for the flash_area_open and ...close to modify the pm state. As all flash area routines are using flash calls anyway to do something isn't the pm of the flash driver sufficient ? |
It is required that the backing device be in the This change lets the flash_map API always work, regardless of the PM state of the backing device. Without this change, every call to Do you have a specific concern about adding this? |
@JordanYates, my concern is that things will be done double (and this is a risk for all subsystems building on top of a driver that has pm): the pm support is already in the driver so any call to the driver will wake it up. The requirement to be in an I don't know if there are other parts of zephyr that are already using a similar pattern. |
Multiple calls to
The |
My concern might have resulted from a incomplete understanding from how the PM API is to be used. I agree that the mapping is clean (I also don't see any objection to the PR). I am trying to understand the "full" implications: a direct flash api call does not call a pm_device_runtime_get() before calling the flash api, but a subsystem using this api does a call to pm_device_runtime_get(): this seems counter intuitive. Suppose the change isn't made, would it no longer operate or operate in a limited fashion ? We shouldn't just add the pm calls because we can, but because we need. This of course raises the question, why is there a |
Suppose a scenario where MCUmgr (and other libraries) are written using the flash map API. They are relatively high level, in that they shouldn't really be caring about the power states of flash chips unless there is no alternative. As long as And from the users perspective, if a library is holding the device in
|
I am getting really scared about pm now:
|
This is embedded, every line of code has the possibility to introduce a system failure. The question is why are you overriding the automatic behaviour of PM? I have used the runtime PM subsystem extensively across multiple applications/boards/years and have never had a problem that wasn't readily apparent within a short duration after boot.
Sure, but by rolling the PM behaviour into the flash map implementation, the only effect on those users is asking them to limit the duration they open an area for. And that is no different from any other API. You don't leave a socket open indefinitely if you're not using it, you don't claim an SPI bus forever. Say when you need it, say when you're done. |
flash map users are saying when they need the device, when there they make a call to So maybe it is just the naming/meaning of the routine ("open") that creates the misunderstanding. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No.
Subsystems may hold flash area indefinitely open and never release it, for example application images and subsystems like settings or file systems.
That will be major headache for low power applications that try to sleep most of a time but keep flash area access enabled.
The pm_device_runtime_get
should be only attempted when the device will really be used. So when operation is attempted.
So your preference is for an implementation more like this? 34322fd |
IMHO only functions that directly use a device should be tasked with waking it up, with some exception I will mention in a moment. There is no reason to manipulate power level of a device by function that just passes pointer to another function because that other function may actually do nothing with the dev and/or just pass it to another function and so on, and finally not action o a device may happen. So basically no There is case for aggressive power management, and I was even considering |
I can appreciate the reasoning, but that is not how any of the device PM API is designed to work AFAIK. The expected flow is:
Are you suggesting that PM should be done in
I'm not sure of the practical difference between doing the PM calls in
That is exactly the type of behaviour that I am trying to enable. An optional step beyond that is "A higher PM level until X seconds after the last call", given that with remote procedures you don't necessarily know which command is the last one, and in many cases multiple flash accesses are tightly grouped in time. |
As far as I understand the https://docs.zephyrproject.org/latest/services/pm/device_runtime.html, the driver is responsible for notifying PM system on device use.
Consider having a device that is woken up once an hour to read several sensors hanging from SPI or other buses. All the readings will happen in q sequence, after which device suspends again. It may be more efficient to elevate the PM level on the path to all devices prior to doing all readings to keep the path active through entire read sequence. Using In my ideal world, device operation like |
I will admit that I haven't previously read through that page closely. While there is a lot of talk about devices requesting themselves, I would like to note two things: First is that the only concrete example given, Second is that no driver that I have seen in-tree is written to run PM operations on itself. And that sort of makes sense, because if that was the case what is the point of having the API in the first place? Just do the work you know you need to do at the start and end of every function. @gmarull wrote the bulk of the current doc version, I would be interested in his opinion.
While this may be fine for internal resources like SPI buses (even if they're not written that way currently) it sort of falls apart IMO as soon as you start considering external devices. Consider a (poorly thought out) power domain that has a GPS modem (slow to initialize, high initial power usage) and a flash chip on it, and we want to run 4 calls to My ideal world is the inverse of yours from what I can tell. In my opinion, higher layers always (ignoring resources automatically controlled by hardware) have a better idea of when a device should be enabled/disabled. A SPI driver is by definition incapable of knowing how higher levels are planning to use it, and unaware of the larger hardware design at play. The same holds for a flash driver, it has 0 idea whether someone is planning to read the status register or write 10MB of data, and hence whether it should be turning itself off now or not. The buck should be passed up the stack until you have a software user that has some idea about the bigger usage picture. I accept that the result will be slightly less efficient power efficient in trivial cases (single flash chip, always powered, single SPI user), but it is actually usable in non-trivial cases with multiple power domains. And when designing for lowest power consumption, the cheapest part to run is the one that has no power applied. |
OK, have another example: you have a file system that opens device at mount and keeps it opened till umount; file system does read/writes in bulks, calling op in a loop. The file system may, before entering loop, elevate PM level of device it is going to do ops on, and lower it when loop exits; PM functions in ops like read/write, for a device, will just increase/decrease counter without actually affecting the PM operation - as the file system driver itself has +1 on it anyway.
For the drivers to call the API, it is for that.
If these are completely separate
Exactly, that is why it should not happen when you gain access to an object representing a device, or reserve it, but rather when you start to use a device. That is why an API call that allow you to notify lower API call too keep device powered, and
SPI driver is used by lower levels: when you ask flash API to read something the flash API takes care of finding the right path to device, whether it is SoC flash or SPI flash, does not matter; you do not know the path and you do not care: you access device by the final node, wherever it is.
That is correct, that is why the flash driver should attempt to control PM level in operations and there should be API to allow to elevate it for unspecified sequence of ops happening in organized manner from single source of upper level. In such case, when the upper level increases device PM level, the calls within device driver will just increase/decrease counters without affecting PM much more; but if you have some random unorganized calls, they still will be covered by PM, without need to directly engage with Power Management. Flash Maps
The problem with "result will be slightly less efficient power efficient in trivial cases" is that these might be the cases that users care a lot, because these may be devices with coin batteries or other limited power sources and locking something into higher power state because it makes other things easier may not be acceptable solution. We will not have efficient power management, in Zephyr, without relying on developers knowledge of device and how user/subsystem uses the device, and user needs to be given a way to control the PM of the device. We can not at the same time cover, without user involvement, without subsystem involvement, and additional PM calls here and there, devices that will be powered by cr2032 and these powered by 1800mAh Li-On, devices that have rough startup and then very small current drawn afterwards and these that have some moderate current drawn through entire time; we can not easily cover operations that happen in bulk and these that happen randomly once a while. |
I am completely inline with the position of @de-nordic: it should be the device (driver) that takes control of the pm. A subsystem that uses a driver could decide to take over the pm by doing a pm_device_get() if it knows it will need many accesses (it is in that case also responsible for the release). A subsystem should be able to rely on the driver pm to do the correct actions without it needing to do any pm actions. Isn't the spi_nor driver an illustration of this ? To allow the subsystem to take over the pm management some routines would need to be defined e.g. |
The |
Taking a step back from the meta discussion around PM.
Great, we both agree that a feature that elevates the PM for a number of sequential operations is desirable, and that is what this PR is attempting to introduce. I see three potential mechanisms for achieving this (with my thoughts in line).
Ensures that "out-of-the-box", any operations using the flash area API will be operating on a device in a valid power state.
Explicit operations that clearly define what they are doing and operates on the native flash area handle.
Workable, but not ideal. The "handle" for the entire flash area API is the flash area itself. Users of flash area currently need no knowledge about devices, and the fact that the backend is a device is an implementation detail that only happens to leak out through a struct member. Has the same downsides as number 2. |
@JordanYates my first reaction is that option 2 is the way to go:
This could be done by either introducing a generic iotcl method or specific routines for doing pm control ( Option 1 is not good because it will disable any power saving when an area is to be used as done by littlefs or nvs. Even when the open/close is done for every Option 3 should be avoided. I see another possibility but I don't know if pm can handle such a scenario: We take option 1, but we add the posibility to "release" the pm from flash_area to the device. Could this be done without creating a state in flash_area that the pm has been "released" ? |
With device runtime PM it is expected that drivers manage themselves (as in Linux). However, it can be used externally if an upper layer wants the device to stay awake between successive calls (to avoid unnecessary sleeps/wakeups during a short sequence). Note that if we had the autosuspend feature (ie, only suspend after a certain inactivity period, say time since last get() call), the last point would probably be mitigated for most cases. |
No it does not. The `Flash Map API is just passing calls to flash driver, the driver does hold PM state by itself, flash area has no interest in current state as it is not going to manipulate it in any of API calls. Any open/close functions should be only used to obtain access to device in form of system provided object, they should not be used for power management as obtaining object does not mean it will be used, it may just be reserved for potential use. |
@de-nordic can you comment on which of the three proposed approaches you find least objectionable? |
I am not that grumpy, I do not find them all objectionable: at least one is OK, I mean the second one with special API calls and open/close untouched. |
Sorry I wasn't implying you're grumpy, I was implying that all 3 have their own drawbacks |
Over 20 years of experience with internet and I still have not figured out there is no voice modulation in a typed text that would suggest that I am trying to be funny-sarcastic. |
DNM till changes applied. |
Adding two cents regarding pm subsystem. I completely agree with @gmarull, it is up to devices to manage themselves, from user perspective is expected that when I need to perform an operation in the device it is active and when it is not being used it is saving energy. Obviously the device itself has limited knowledge of how it will be used, so the upper layer can optimize this getting/releasing the device. I think the general (obviously there are exceptions) assumption should be, if the device is not doing a hw operation at the moment it is suspended. This kind of transfer part of the responsibility to the upper layer (avoid unnecessary suspend/resume), but that will always be the case, since as higher you are more knowledge of the application you have. |
Run power management actions in
flash_area_open
andflash_area_close
. If the flash area is open it should be in the activestate, otherwise it should be left in its lowest power state.