• Russell King's avatar
    ARM: fix broken hibernation · 33c40643
    Russell King authored
    commit 767bf7e7 upstream.
    
    Normally, when a CPU wants to clear a cache line to zero in the external
    L2 cache, it would generate bus cycles to write each word as it would do
    with any other data access.
    
    However, a Cortex A9 connected to a L2C-310 has a specific feature where
    the CPU can detect this operation, and signal that it wants to zero an
    entire cache line.  This feature, known as Full Line of Zeros (FLZ),
    involves a non-standard AXI signalling mechanism which only the L2C-310
    can properly interpret.
    
    There are separate enable bits in both the L2C-310 and the Cortex A9 -
    the L2C-310 needs to be enabled and have the FLZ enable bit set in the
    auxiliary control register before the Cortex A9 has this feature
    enabled.
    
    Unfortunately, the suspend code was not respecting this - it's not
    obvious from the code:
    
    swsusp_arch_suspend()
     cpu_suspend() /* saves the Cortex A9 auxiliary control register */
      arch_save_image()
      soft_restart() /* turns off FLZ in Cortex A9, and disables L2C */
       cpu_resume() /* restores the Cortex A9 registers, inc auxcr */
    
    At this point, we end up with the L2C disabled, but the Cortex A9 with
    FLZ enabled - which means any memset() or zeroing of a full cache line
    will fail to take effect.
    
    A similar issue exists in the resume path, but it's slightly more
    complex:
    
    swsusp_arch_suspend()
     cpu_suspend() /* saves the Cortex A9 auxiliary control register */
      arch_save_image() /* image with A9 auxcr saved */
    ...
    swsusp_arch_resume()
     call_with_stack()
      arch_restore_image() /* restores image with A9 auxcr saved above */
      soft_restart() /* turns off FLZ in Cortex A9, and disables L2C */
       cpu_resume() /* restores the Cortex A9 registers, inc auxcr */
    
    Again, here we end up with the L2C disabled, but Cortex A9 FLZ enabled.
    
    There's no need to turn off the L2C in either of these two paths; there
    are benefits from not doing so - for example, the page copies will be
    faster with the L2C enabled.
    
    Hence, fix this by providing a variant of soft_restart() which can be
    used without turning the L2 cache controller off, and use it in both
    of these paths to keep the L2C enabled across the respective resume
    transitions.
    
    Fixes: 8ef418c7 ("ARM: l2c: trial at enabling some Cortex-A9 optimisations")
    Reported-by: default avatarSean Cross <xobs@kosagi.com>
    Tested-by: default avatarSean Cross <xobs@kosagi.com>
    Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
    [ luis: backported to 3.16: adjusted context ]
    Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
    33c40643
hibernate.c 2.85 KB