This patch adds CONFIG_HIBERNATION support for sparc64
architecture. The suspend function is the same as on another
platforms. The restore function uses Bypass feature of MMU
which allows to make the process more comfortable and plesant.

Signed-off-by: Kirill Tkhai <tkhai@yandex.ru>
CC: David Miller <davem@davemloft.net>
CC: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Tkhai Kirill 2013-03-19 15:11:07 +00:00 коммит произвёл David S. Miller
Родитель 1ab0a67601
Коммит bdde6b3c8b
7 изменённых файлов: 222 добавлений и 0 удалений

Просмотреть файл

@ -100,6 +100,9 @@ config HAVE_LATENCYTOP_SUPPORT
bool
default y if SPARC64
config ARCH_HIBERNATION_POSSIBLE
def_bool y if SPARC64
config AUDIT_ARCH
bool
default y
@ -327,6 +330,10 @@ config ARCH_SPARSEMEM_DEFAULT
source "mm/Kconfig"
if SPARC64
source "kernel/power/Kconfig"
endif
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
depends on SPARC64 && SMP

Просмотреть файл

@ -57,6 +57,7 @@ core-y += arch/sparc/
libs-y += arch/sparc/prom/
libs-y += arch/sparc/lib/
drivers-$(CONFIG_PM) += arch/sparc/power/
drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/
boot := arch/sparc/boot

Просмотреть файл

@ -0,0 +1,23 @@
/*
* hibernate.h: Hibernaton support specific for sparc64.
*
* Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru)
*/
#ifndef ___SPARC_HIBERNATE_H
#define ___SPARC_HIBERNATE_H
struct saved_context {
unsigned long fp;
unsigned long cwp;
unsigned long wstate;
unsigned long tick;
unsigned long pstate;
unsigned long g4;
unsigned long g5;
unsigned long g6;
};
#endif

Просмотреть файл

@ -14,6 +14,8 @@
// #include <linux/mm.h>
#include <linux/kbuild.h>
#include <asm/hibernate.h>
#ifdef CONFIG_SPARC32
int sparc32_foo(void)
{
@ -24,6 +26,19 @@ int sparc32_foo(void)
#else
int sparc64_foo(void)
{
#ifdef CONFIG_HIBERNATION
BLANK();
OFFSET(SC_REG_FP, saved_context, fp);
OFFSET(SC_REG_CWP, saved_context, cwp);
OFFSET(SC_REG_WSTATE, saved_context, wstate);
OFFSET(SC_REG_TICK, saved_context, tick);
OFFSET(SC_REG_PSTATE, saved_context, pstate);
OFFSET(SC_REG_G4, saved_context, g4);
OFFSET(SC_REG_G5, saved_context, g5);
OFFSET(SC_REG_G6, saved_context, g6);
#endif
return 0;
}
#endif

Просмотреть файл

@ -0,0 +1,3 @@
# Makefile for Sparc-specific hibernate files.
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o

Просмотреть файл

@ -0,0 +1,42 @@
/*
* hibernate.c: Hibernaton support specific for sparc64.
*
* Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru)
*/
#include <linux/mm.h>
#include <asm/hibernate.h>
#include <asm/visasm.h>
#include <asm/page.h>
#include <asm/tlb.h>
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
struct saved_context saved_context;
/*
* pfn_is_nosave - check if given pfn is in the 'nosave' section
*/
int pfn_is_nosave(unsigned long pfn)
{
unsigned long nosave_begin_pfn = PFN_DOWN((unsigned long)&__nosave_begin);
unsigned long nosave_end_pfn = PFN_DOWN((unsigned long)&__nosave_end);
return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
}
void save_processor_state(void)
{
save_and_clear_fpu();
}
void restore_processor_state(void)
{
struct mm_struct *mm = current->active_mm;
load_secondary_context(mm);
tsb_context_switch(mm);
}

Просмотреть файл

@ -0,0 +1,131 @@
/*
* hibernate_asm.S: Hibernaton support specific for sparc64.
*
* Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru)
*/
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/cpudata.h>
#include <asm/page.h>
ENTRY(swsusp_arch_suspend)
save %sp, -128, %sp
save %sp, -128, %sp
flushw
setuw saved_context, %g3
/* Save window regs */
rdpr %cwp, %g2
stx %g2, [%g3 + SC_REG_CWP]
rdpr %wstate, %g2
stx %g2, [%g3 + SC_REG_WSTATE]
stx %fp, [%g3 + SC_REG_FP]
/* Save state regs */
rdpr %tick, %g2
stx %g2, [%g3 + SC_REG_TICK]
rdpr %pstate, %g2
stx %g2, [%g3 + SC_REG_PSTATE]
/* Save global regs */
stx %g4, [%g3 + SC_REG_G4]
stx %g5, [%g3 + SC_REG_G5]
stx %g6, [%g3 + SC_REG_G6]
call swsusp_save
nop
mov %o0, %i0
restore
mov %o0, %i0
ret
restore
ENTRY(swsusp_arch_resume)
/* Write restore_pblist to %l0 */
sethi %hi(restore_pblist), %l0
ldx [%l0 + %lo(restore_pblist)], %l0
call __flush_tlb_all
nop
/* Write PAGE_OFFSET to %g7 */
sethi %uhi(PAGE_OFFSET), %g7
sllx %g7, 32, %g7
setuw (PAGE_SIZE-8), %g3
/* Use MMU Bypass */
rd %asi, %g1
wr %g0, ASI_PHYS_USE_EC, %asi
ba fill_itlb
nop
pbe_loop:
cmp %l0, %g0
be restore_ctx
sub %l0, %g7, %l0
ldxa [%l0 ] %asi, %l1 /* address */
ldxa [%l0 + 8] %asi, %l2 /* orig_address */
/* phys addr */
sub %l1, %g7, %l1
sub %l2, %g7, %l2
mov %g3, %l3 /* PAGE_SIZE-8 */
copy_loop:
ldxa [%l1 + %l3] ASI_PHYS_USE_EC, %g2
stxa %g2, [%l2 + %l3] ASI_PHYS_USE_EC
cmp %l3, %g0
bne copy_loop
sub %l3, 8, %l3
/* next pbe */
ba pbe_loop
ldxa [%l0 + 16] %asi, %l0
restore_ctx:
setuw saved_context, %g3
/* Restore window regs */
wrpr %g0, 0, %canrestore
wrpr %g0, 0, %otherwin
wrpr %g0, 6, %cansave
wrpr %g0, 0, %cleanwin
ldxa [%g3 + SC_REG_CWP] %asi, %g2
wrpr %g2, %cwp
ldxa [%g3 + SC_REG_WSTATE] %asi, %g2
wrpr %g2, %wstate
ldxa [%g3 + SC_REG_FP] %asi, %fp
/* Restore state regs */
ldxa [%g3 + SC_REG_PSTATE] %asi, %g2
wrpr %g2, %pstate
ldxa [%g3 + SC_REG_TICK] %asi, %g2
wrpr %g2, %tick
/* Restore global regs */
ldxa [%g3 + SC_REG_G4] %asi, %g4
ldxa [%g3 + SC_REG_G5] %asi, %g5
ldxa [%g3 + SC_REG_G6] %asi, %g6
wr %g1, %g0, %asi
restore
restore
wrpr %g0, 14, %pil
retl
mov %g0, %o0
fill_itlb:
ba pbe_loop
wrpr %g0, 15, %pil