Hi Kevin, a few comments: On Tue, 6 Apr 2010, Kevin Hilman wrote: > Add new function omap_device_has_lost_context() as a simple check > to be used after omap_device_enable() to determine if device has > lost context (and thus needs context restore.) > > Motivation: Currently, each driver needs to read the context-loss > count before suspend, and again upon resume to determine if > device context needs to be restored. Rather than duplicating > this process across all drivers, move it into omap_device. After > omap_device_enable(), omap_device_has_lost_context() can be called > to determine if context was lost. > > The hard work is done inside the powerdomain layer where a simple flag > is checked. The flag is cleared in the pre-transition call back, > and conditionally set post-transition based on either an off-mode > transition or a memory or logic off transition. > > Signed-off-by: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx> Wouldn't this need to be set/cleared on a per-device basis? Certainly the process of setting the flag to true is most efficiently done on a per-powerdomain basis, but clearing the flag to false can only be done after the driver reloads the device context. The powerdomain layer won't know about that. Similarly, based on a quick glance, it looks like this code could miss a situation where a powerdomain goes off, loses context, then comes back on and does another transition from ON to CSWR or something similar that causes pwrdm->lost_context to be set to false. If a driver calls omap_device_has_lost_context(), wouldn't it return false, even though the device context may still be lost? Thinking about the problem naively, I'd guess that it would be best to iterate over all the struct omap_devices in that powerdomain when the system notices that the device context has been lost and set a per-device context loss flag to true. Then the driver's context-restore code would also need to call into another function after the restore is complete, something like omap_device_context_restored(), which would set the per-device flag to true. There might need to be an exception flag set in some hwmods that would indicate that the hardware restores some contexts by itself, such as SDRC, etc. Also, is it possible for a completely idle powerdomain with clockdomains in hardware-supervised idle and with a next-power-state of OSWR or OFF to lose its context at any point, e.g., even if the MPU hasn't hit WFI? If so, then this context-loss flag would pretty much need to be set the moment that the last functional clock goes off in that powerdomain (assuming that there are no modules in no-idle). I guess we could also check the powerdomain's previous power state flag when the first clock is switched back on in the powerdomain. > --- > arch/arm/mach-omap2/powerdomain.c | 11 +++++++- > arch/arm/plat-omap/include/plat/omap_device.h | 1 + > arch/arm/plat-omap/include/plat/powerdomain.h | 2 +- > arch/arm/plat-omap/omap_device.c | 29 +++++++++++++++++++++++++ > 4 files changed, 40 insertions(+), 3 deletions(-) > > diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c > index 9a0fb38..ac54607 100644 > --- a/arch/arm/mach-omap2/powerdomain.c > +++ b/arch/arm/mach-omap2/powerdomain.c > @@ -145,15 +145,19 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm) > > prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm); > if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) && > - (prev_logic_pwrst == PWRDM_POWER_OFF)) > + (prev_logic_pwrst == PWRDM_POWER_OFF)) { > pwrdm->ret_logic_off_counter++; > + pwrdm->lost_context = true; > + } > > for (i = 0; i < pwrdm->banks; i++) { > prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i); > > if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) && > - (prev_mem_pwrst == PWRDM_POWER_OFF)) > + (prev_mem_pwrst == PWRDM_POWER_OFF)) { > pwrdm->ret_mem_off_counter[i]++; > + pwrdm->lost_context = true; > + } > } > } > > @@ -176,6 +180,8 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) > prev = pwrdm_read_prev_pwrst(pwrdm); > if (pwrdm->state != prev) > pwrdm->state_counter[prev]++; > + if (prev == PWRDM_POWER_OFF) > + pwrdm->lost_context = true; > if (prev == PWRDM_POWER_RET) > _update_logic_membank_counters(pwrdm); > break; > @@ -197,6 +203,7 @@ static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused) > { > pwrdm_clear_all_prev_pwrst(pwrdm); > _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); > + pwrdm->lost_context = false; > return 0; > } > > diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h > index 3694b62..b6ef94c 100644 > --- a/arch/arm/plat-omap/include/plat/omap_device.h > +++ b/arch/arm/plat-omap/include/plat/omap_device.h > @@ -79,6 +79,7 @@ struct omap_device { > int omap_device_enable(struct platform_device *pdev); > int omap_device_idle(struct platform_device *pdev); > int omap_device_shutdown(struct platform_device *pdev); > +bool omap_device_has_lost_context(struct platform_device *pdev); > > /* Core code interface */ > > diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h > index d82b2c0..bd5ab48 100644 > --- a/arch/arm/plat-omap/include/plat/powerdomain.h > +++ b/arch/arm/plat-omap/include/plat/powerdomain.h > @@ -102,7 +102,7 @@ struct powerdomain { > unsigned state_counter[PWRDM_MAX_PWRSTS]; > unsigned ret_logic_off_counter; > unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; > - > + bool lost_context; > #ifdef CONFIG_PM_DEBUG > s64 timer; > s64 state_timer[PWRDM_MAX_PWRSTS]; > diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c > index 5904358..0340b40 100644 > --- a/arch/arm/plat-omap/omap_device.c > +++ b/arch/arm/plat-omap/omap_device.c > @@ -84,6 +84,7 @@ > > #include <plat/omap_device.h> > #include <plat/omap_hwmod.h> > +#include <plat/powerdomain.h> > > /* These parameters are passed to _omap_device_{de,}activate() */ > #define USE_WAKEUP_LAT 0 > @@ -579,6 +580,34 @@ int omap_device_shutdown(struct platform_device *pdev) > } > > /** > + * omap_device_has_lost_context() - check if omap_device has lost context > + * @od: struct omap_device * > + * > + * When an omap_device has been deactivated via omap_device_idle() or > + * omap_device_shutdown() and then (re)activated using omap_device_enable() > + * This function should be used to determine if the omap_device has > + * lost context (due to an off-mode transistion) > + */ > +bool omap_device_has_lost_context(struct platform_device *pdev) > +{ > + struct omap_device *od; > + struct powerdomain *pwrdm; > + > + od = _find_by_pdev(pdev); > + > + if (od->_state != OMAP_DEVICE_STATE_ENABLED) { > + WARN(1, "omap_device: %s.%d: has_lost_context() called " > + "from invalid state\n", od->pdev.name, od->pdev.id); > + return -EINVAL; > + } > + pwrdm = omap_device_get_pwrdm(od); > + if (pwrdm) > + return pwrdm->lost_context; > + > + return false; > +} > + > +/** > * omap_device_align_pm_lat - activate/deactivate device to match wakeup lat lim > * @od: struct omap_device * > * > -- > 1.7.0.2 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > - Paul -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html