Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2014 Imagination Technologies Ltd.
0004  *
0005  * CPU PM notifiers for saving/restoring general CPU state.
0006  */
0007 
0008 #include <linux/cpu_pm.h>
0009 #include <linux/init.h>
0010 
0011 #include <asm/dsp.h>
0012 #include <asm/fpu.h>
0013 #include <asm/mmu_context.h>
0014 #include <asm/pm.h>
0015 #include <asm/watch.h>
0016 
0017 /* Used by PM helper macros in asm/pm.h */
0018 struct mips_static_suspend_state mips_static_suspend_state;
0019 
0020 /**
0021  * mips_cpu_save() - Save general CPU state.
0022  * Ensures that general CPU context is saved, notably FPU and DSP.
0023  */
0024 static int mips_cpu_save(void)
0025 {
0026     /* Save FPU state */
0027     lose_fpu(1);
0028 
0029     /* Save DSP state */
0030     save_dsp(current);
0031 
0032     return 0;
0033 }
0034 
0035 /**
0036  * mips_cpu_restore() - Restore general CPU state.
0037  * Restores important CPU context.
0038  */
0039 static void mips_cpu_restore(void)
0040 {
0041     unsigned int cpu = smp_processor_id();
0042 
0043     /* Restore ASID */
0044     if (current->mm)
0045         write_c0_entryhi(cpu_asid(cpu, current->mm));
0046 
0047     /* Restore DSP state */
0048     restore_dsp(current);
0049 
0050     /* Restore UserLocal */
0051     if (cpu_has_userlocal)
0052         write_c0_userlocal(current_thread_info()->tp_value);
0053 
0054     /* Restore watch registers */
0055     __restore_watch(current);
0056 }
0057 
0058 /**
0059  * mips_pm_notifier() - Notifier for preserving general CPU context.
0060  * @self:   Notifier block.
0061  * @cmd:    CPU PM event.
0062  * @v:      Private data (unused).
0063  *
0064  * This is called when a CPU power management event occurs, and is used to
0065  * ensure that important CPU context is preserved across a CPU power down.
0066  */
0067 static int mips_pm_notifier(struct notifier_block *self, unsigned long cmd,
0068                 void *v)
0069 {
0070     int ret;
0071 
0072     switch (cmd) {
0073     case CPU_PM_ENTER:
0074         ret = mips_cpu_save();
0075         if (ret)
0076             return NOTIFY_STOP;
0077         break;
0078     case CPU_PM_ENTER_FAILED:
0079     case CPU_PM_EXIT:
0080         mips_cpu_restore();
0081         break;
0082     }
0083 
0084     return NOTIFY_OK;
0085 }
0086 
0087 static struct notifier_block mips_pm_notifier_block = {
0088     .notifier_call = mips_pm_notifier,
0089 };
0090 
0091 static int __init mips_pm_init(void)
0092 {
0093     return cpu_pm_register_notifier(&mips_pm_notifier_block);
0094 }
0095 arch_initcall(mips_pm_init);