Skip to content

Commit

Permalink
Merge tag 'arm64-suspend' of git://linux-arm.org/linux-2.6-lp into up…
Browse files Browse the repository at this point in the history
…stream

* tag 'arm64-suspend' of git://linux-arm.org/linux-2.6-lp:
  arm64: add CPU power management menu/entries
  arm64: kernel: add PM build infrastructure
  arm64: kernel: add CPU idle call
  arm64: enable generic clockevent broadcast
  arm64: kernel: implement HW breakpoints CPU PM notifier
  arm64: kernel: refactor code to install/uninstall breakpoints
  arm: kvm: implement CPU PM notifier
  arm64: kernel: implement fpsimd CPU PM notifier
  arm64: kernel: cpu_{suspend/resume} implementation
  arm64: kernel: suspend/resume registers save/restore
  arm64: kernel: build MPIDR_EL1 hash function data structure
  arm64: kernel: add MPIDR_EL1 accessors macros

Conflicts:
	arch/arm64/Kconfig
  • Loading branch information
ctmarinas committed Dec 19, 2013
2 parents 6ac2104 + 1307220 commit 0a5be74
Show file tree
Hide file tree
Showing 18 changed files with 767 additions and 70 deletions.
30 changes: 30 additions & 0 deletions arch/arm/kvm/arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

#include <linux/cpu.h>
#include <linux/cpu_pm.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/kvm_host.h>
Expand Down Expand Up @@ -853,6 +854,33 @@ static struct notifier_block hyp_init_cpu_nb = {
.notifier_call = hyp_init_cpu_notify,
};

#ifdef CONFIG_CPU_PM
static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
unsigned long cmd,
void *v)
{
if (cmd == CPU_PM_EXIT) {
cpu_init_hyp_mode(NULL);
return NOTIFY_OK;
}

return NOTIFY_DONE;
}

static struct notifier_block hyp_init_cpu_pm_nb = {
.notifier_call = hyp_init_cpu_pm_notifier,
};

static void __init hyp_cpu_pm_init(void)
{
cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
}
#else
static inline void hyp_cpu_pm_init(void)
{
}
#endif

/**
* Inits Hyp-mode on all online CPUs
*/
Expand Down Expand Up @@ -1013,6 +1041,8 @@ int kvm_arch_init(void *opaque)
goto out_err;
}

hyp_cpu_pm_init();

kvm_coproc_table_init();
return 0;
out_err:
Expand Down
21 changes: 21 additions & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ config ARM64
def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
select ARCH_WANT_FRAME_POINTERS
Expand All @@ -11,8 +12,10 @@ config ARM64
select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
select COMMON_CLK
select CPU_PM if (SUSPEND || CPU_IDLE)
select DCACHE_WORD_ACCESS
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select GENERIC_IOMAP
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
Expand Down Expand Up @@ -280,6 +283,24 @@ config SYSVIPC_COMPAT

endmenu

menu "Power management options"

source "kernel/power/Kconfig"

config ARCH_SUSPEND_POSSIBLE
def_bool y

config ARM64_CPU_SUSPEND
def_bool PM_SLEEP

endmenu

menu "CPU Power Management"

source "drivers/cpuidle/Kconfig"

endmenu

source "net/Kconfig"

source "drivers/Kconfig"
Expand Down
6 changes: 6 additions & 0 deletions arch/arm64/include/asm/cpu_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ struct device_node;
* from the cpu to be killed.
* @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the
* cpu being killed.
* @cpu_suspend: Suspends a cpu and saves the required context. May fail owing
* to wrong parameters or error conditions. Called from the
* CPU being suspended. Must be called with IRQs disabled.
*/
struct cpu_operations {
const char *name;
Expand All @@ -50,6 +53,9 @@ struct cpu_operations {
int (*cpu_disable)(unsigned int cpu);
void (*cpu_die)(unsigned int cpu);
#endif
#ifdef CONFIG_ARM64_CPU_SUSPEND
int (*cpu_suspend)(unsigned long);
#endif
};

extern const struct cpu_operations *cpu_ops[NR_CPUS];
Expand Down
10 changes: 10 additions & 0 deletions arch/arm64/include/asm/cputype.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@

#define MPIDR_HWID_BITMASK 0xff00ffffff

#define MPIDR_LEVEL_BITS_SHIFT 3
#define MPIDR_LEVEL_BITS (1 << MPIDR_LEVEL_BITS_SHIFT)
#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1)

#define MPIDR_LEVEL_SHIFT(level) \
(((1 << level) >> 1) << MPIDR_LEVEL_BITS_SHIFT)

#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK)

#define read_cpuid(reg) ({ \
u64 __val; \
asm("mrs %0, " #reg : "=r" (__val)); \
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/include/asm/hardirq.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include <linux/threads.h>
#include <asm/irq.h>

#define NR_IPI 4
#define NR_IPI 5

typedef struct {
unsigned int __softirq_pending;
Expand Down
3 changes: 3 additions & 0 deletions arch/arm64/include/asm/proc-fns.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@
#include <asm/page.h>

struct mm_struct;
struct cpu_suspend_ctx;

extern void cpu_cache_off(void);
extern void cpu_do_idle(void);
extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr);
extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);

#include <asm/memory.h>

Expand Down
13 changes: 13 additions & 0 deletions arch/arm64/include/asm/smp_plat.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@

#include <asm/types.h>

struct mpidr_hash {
u64 mask;
u32 shift_aff[4];
u32 bits;
};

extern struct mpidr_hash mpidr_hash;

static inline u32 mpidr_hash_size(void)
{
return 1 << mpidr_hash.bits;
}

/*
* Logical CPU mapping.
*/
Expand Down
27 changes: 27 additions & 0 deletions arch/arm64/include/asm/suspend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef __ASM_SUSPEND_H
#define __ASM_SUSPEND_H

#define NR_CTX_REGS 11

/*
* struct cpu_suspend_ctx must be 16-byte aligned since it is allocated on
* the stack, which must be 16-byte aligned on v8
*/
struct cpu_suspend_ctx {
/*
* This struct must be kept in sync with
* cpu_do_{suspend/resume} in mm/proc.S
*/
u64 ctx_regs[NR_CTX_REGS];
u64 sp;
} __aligned(16);

struct sleep_save_sp {
phys_addr_t *save_ptr_stash;
phys_addr_t save_ptr_stash_phys;
};

extern void cpu_resume(void);
extern int cpu_suspend(unsigned long);

#endif
1 change: 1 addition & 0 deletions arch/arm64/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o

obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
Expand Down
11 changes: 11 additions & 0 deletions arch/arm64/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/cputable.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include <asm/vdso_datapage.h>
#include <linux/kbuild.h>

Expand Down Expand Up @@ -137,6 +139,15 @@ int main(void)
DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
#endif
#ifdef CONFIG_ARM64_CPU_SUSPEND
DEFINE(CPU_SUSPEND_SZ, sizeof(struct cpu_suspend_ctx));
DEFINE(CPU_CTX_SP, offsetof(struct cpu_suspend_ctx, sp));
DEFINE(MPIDR_HASH_MASK, offsetof(struct mpidr_hash, mask));
DEFINE(MPIDR_HASH_SHIFTS, offsetof(struct mpidr_hash, shift_aff));
DEFINE(SLEEP_SAVE_SP_SZ, sizeof(struct sleep_save_sp));
DEFINE(SLEEP_SAVE_SP_PHYS, offsetof(struct sleep_save_sp, save_ptr_stash_phys));
DEFINE(SLEEP_SAVE_SP_VIRT, offsetof(struct sleep_save_sp, save_ptr_stash));
#endif
return 0;
}
36 changes: 36 additions & 0 deletions arch/arm64/kernel/fpsimd.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <linux/cpu_pm.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
Expand Down Expand Up @@ -113,6 +114,39 @@ EXPORT_SYMBOL(kernel_neon_end);

#endif /* CONFIG_KERNEL_MODE_NEON */

#ifdef CONFIG_CPU_PM
static int fpsimd_cpu_pm_notifier(struct notifier_block *self,
unsigned long cmd, void *v)
{
switch (cmd) {
case CPU_PM_ENTER:
if (current->mm)
fpsimd_save_state(&current->thread.fpsimd_state);
break;
case CPU_PM_EXIT:
if (current->mm)
fpsimd_load_state(&current->thread.fpsimd_state);
break;
case CPU_PM_ENTER_FAILED:
default:
return NOTIFY_DONE;
}
return NOTIFY_OK;
}

static struct notifier_block fpsimd_cpu_pm_notifier_block = {
.notifier_call = fpsimd_cpu_pm_notifier,
};

static void fpsimd_pm_init(void)
{
cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block);
}

#else
static inline void fpsimd_pm_init(void) { }
#endif /* CONFIG_CPU_PM */

/*
* FP/SIMD support code initialisation.
*/
Expand All @@ -131,6 +165,8 @@ static int __init fpsimd_init(void)
else
elf_hwcap |= HWCAP_ASIMD;

fpsimd_pm_init();

return 0;
}
late_initcall(fpsimd_init);
Loading

0 comments on commit 0a5be74

Please sign in to comment.